Skip to content

Commit

Permalink
KCL: Show beautiful Miette errors when a KCL example test fails (#4829)
Browse files Browse the repository at this point in the history
* KCL: Show beautiful Miette errors when a KCL example test fails

Background: KCL example tests are generated from the stdlib KCL examples in the `#[stdlib]` macro in derive-docs.

Problem: When these tests fail, they output a really unhelpful error message like Kcl(Semantic(KclErrorDetails { source_ranges: [156, 160, 0], message: "Expected a sketch but found array" } )).

Solution: Use miette. Now the errors highlight the KCL code that failed and show exactly what went wrong, on which line, presenting nice diagnostics that look like cargo/rustc output.

* Update helix snapshots
  • Loading branch information
adamchalmers authored Dec 18, 2024
1 parent 7193b41 commit 9389142
Show file tree
Hide file tree
Showing 19 changed files with 431 additions and 124 deletions.
2 changes: 1 addition & 1 deletion docs/kcl/helix.md

Large diffs are not rendered by default.

26 changes: 22 additions & 4 deletions src/wasm-lib/derive-docs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr

quote! {
#[tokio::test(flavor = "multi_thread")]
async fn #test_name_mock() {
async fn #test_name_mock() -> miette::Result<()> {
let program = crate::Program::parse_no_errs(#code_block).unwrap();
let ctx = crate::ExecutorContext {
engine: std::sync::Arc::new(Box::new(crate::engine::conn_mock::EngineConnection::new().await.unwrap())),
Expand All @@ -815,15 +815,33 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
context_type: crate::execution::ContextType::Mock,
};

ctx.run(program.into(), &mut crate::ExecState::new()).await.unwrap();
if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new()).await {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", #fn_name, #index),
kcl_source: #code_block.to_string(),
}));
}
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn #test_name() {
async fn #test_name() -> miette::Result<()> {
let code = #code_block;
// Note, `crate` must be kcl_lib
let result = crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm, None).await.unwrap();
let result = match crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", #fn_name, #index),
kcl_source: #code_block.to_string(),
}));
}
Err(other_err)=> panic!("{}", other_err),
Ok(img) => img,
};
twenty_twenty::assert_image(&format!("tests/outputs/{}.png", #output_test_name_str), &result, 0.99);
Ok(())
}
}
}
31 changes: 24 additions & 7 deletions src/wasm-lib/derive-docs/tests/args_with_lifetime.gen
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(test)]
mod test_examples_someFn {
#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_someFn0() {
async fn test_mock_example_someFn0() -> miette::Result<()> {
let program = crate::Program::parse_no_errs("someFn()").unwrap();
let ctx = crate::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
Expand All @@ -14,26 +14,43 @@ mod test_examples_someFn {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new()).await {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "someFn", 0usize),
kcl_source: "someFn()".to_string(),
}));
}

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_someFn0() {
async fn kcl_test_example_someFn0() -> miette::Result<()> {
let code = "someFn()";
let result = crate::test_server::execute_and_snapshot(
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
.unwrap();
{
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "someFn", 0usize),
kcl_source: "someFn()".to_string(),
}));
}
Err(other_err) => panic!("{}", other_err),
Ok(img) => img,
};
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
&result,
0.99,
);
Ok(())
}
}

Expand Down
31 changes: 24 additions & 7 deletions src/wasm-lib/derive-docs/tests/args_with_refs.gen
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(test)]
mod test_examples_someFn {
#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_someFn0() {
async fn test_mock_example_someFn0() -> miette::Result<()> {
let program = crate::Program::parse_no_errs("someFn()").unwrap();
let ctx = crate::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
Expand All @@ -14,26 +14,43 @@ mod test_examples_someFn {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new()).await {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "someFn", 0usize),
kcl_source: "someFn()".to_string(),
}));
}

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_someFn0() {
async fn kcl_test_example_someFn0() -> miette::Result<()> {
let code = "someFn()";
let result = crate::test_server::execute_and_snapshot(
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
.unwrap();
{
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "someFn", 0usize),
kcl_source: "someFn()".to_string(),
}));
}
Err(other_err) => panic!("{}", other_err),
Ok(img) => img,
};
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
&result,
0.99,
);
Ok(())
}
}

Expand Down
62 changes: 48 additions & 14 deletions src/wasm-lib/derive-docs/tests/array.gen
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(test)]
mod test_examples_show {
#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_show0() {
async fn test_mock_example_show0() -> miette::Result<()> {
let program =
crate::Program::parse_no_errs("This is another code block.\nyes sirrr.\nshow").unwrap();
let ctx = crate::ExecutorContext {
Expand All @@ -15,30 +15,47 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new()).await {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "show", 0usize),
kcl_source: "This is another code block.\nyes sirrr.\nshow".to_string(),
}));
}

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_show0() {
async fn kcl_test_example_show0() -> miette::Result<()> {
let code = "This is another code block.\nyes sirrr.\nshow";
let result = crate::test_server::execute_and_snapshot(
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
.unwrap();
{
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "show", 0usize),
kcl_source: "This is another code block.\nyes sirrr.\nshow".to_string(),
}));
}
Err(other_err) => panic!("{}", other_err),
Ok(img) => img,
};
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
&result,
0.99,
);
Ok(())
}

#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_show1() {
async fn test_mock_example_show1() -> miette::Result<()> {
let program =
crate::Program::parse_no_errs("This is code.\nIt does other shit.\nshow").unwrap();
let ctx = crate::ExecutorContext {
Expand All @@ -52,26 +69,43 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new()).await {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "show", 1usize),
kcl_source: "This is code.\nIt does other shit.\nshow".to_string(),
}));
}

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_show1() {
async fn kcl_test_example_show1() -> miette::Result<()> {
let code = "This is code.\nIt does other shit.\nshow";
let result = crate::test_server::execute_and_snapshot(
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
.unwrap();
{
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "show", 1usize),
kcl_source: "This is code.\nIt does other shit.\nshow".to_string(),
}));
}
Err(other_err) => panic!("{}", other_err),
Ok(img) => img,
};
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show1"),
&result,
0.99,
);
Ok(())
}
}

Expand Down
31 changes: 24 additions & 7 deletions src/wasm-lib/derive-docs/tests/box.gen
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(test)]
mod test_examples_show {
#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_show0() {
async fn test_mock_example_show0() -> miette::Result<()> {
let program =
crate::Program::parse_no_errs("This is code.\nIt does other shit.\nshow").unwrap();
let ctx = crate::ExecutorContext {
Expand All @@ -15,26 +15,43 @@ mod test_examples_show {
settings: Default::default(),
context_type: crate::execution::ContextType::Mock,
};
ctx.run(program.into(), &mut crate::ExecState::new())
.await
.unwrap();
if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new()).await {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "show", 0usize),
kcl_source: "This is code.\nIt does other shit.\nshow".to_string(),
}));
}

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_show0() {
async fn kcl_test_example_show0() -> miette::Result<()> {
let code = "This is code.\nIt does other shit.\nshow";
let result = crate::test_server::execute_and_snapshot(
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
.unwrap();
{
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e,
filename: format!("{}{}", "show", 0usize),
kcl_source: "This is code.\nIt does other shit.\nshow".to_string(),
}));
}
Err(other_err) => panic!("{}", other_err),
Ok(img) => img,
};
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
&result,
0.99,
);
Ok(())
}
}

Expand Down
Loading

0 comments on commit 9389142

Please sign in to comment.