diff --git a/Cargo.toml b/Cargo.toml index 95c956d5..90297f29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,11 +103,15 @@ todo = "deny" unimplemented = "deny" unreachable = "deny" -[profile.dev.package."*"] -opt-level = 2 - +# Workspace crates keep file:line in panic backtraces; dependencies carry no debug info. Both make +# the test build faster and the target dir smaller. [profile.dev] opt-level = 1 +debug = "line-tables-only" + +[profile.dev.package."*"] +opt-level = 2 +debug = false [profile.release] lto = "thin" diff --git a/apps/figcraft-cli/tests/cli.rs b/apps/figcraft-cli/tests/it/cli.rs similarity index 99% rename from apps/figcraft-cli/tests/cli.rs rename to apps/figcraft-cli/tests/it/cli.rs index eb42b8d8..4af73d69 100644 --- a/apps/figcraft-cli/tests/cli.rs +++ b/apps/figcraft-cli/tests/it/cli.rs @@ -1,5 +1,4 @@ //! The binary end to end. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::io::Write; use std::process::{Command, Stdio}; diff --git a/apps/figcraft-cli/tests/export_depth.rs b/apps/figcraft-cli/tests/it/export_depth.rs similarity index 97% rename from apps/figcraft-cli/tests/export_depth.rs rename to apps/figcraft-cli/tests/it/export_depth.rs index d8b3ef36..37350c1e 100644 --- a/apps/figcraft-cli/tests/export_depth.rs +++ b/apps/figcraft-cli/tests/it/export_depth.rs @@ -1,5 +1,4 @@ //! Depth refusal through the actual CLI, including its exit status and destination writes. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use figcraft_doc::color::{Color, Paint}; use figcraft_doc::{Document, NodeKind}; diff --git a/apps/figcraft-cli/tests/fonts.rs b/apps/figcraft-cli/tests/it/fonts.rs similarity index 98% rename from apps/figcraft-cli/tests/fonts.rs rename to apps/figcraft-cli/tests/it/fonts.rs index ef5c638f..a48056bd 100644 --- a/apps/figcraft-cli/tests/fonts.rs +++ b/apps/figcraft-cli/tests/it/fonts.rs @@ -1,6 +1,5 @@ //! Headless runs lay text out with the installed fonts, like the desktop app, unless //! `--no-system-fonts` or `FIGCRAFT_NO_SYSTEM_FONTS=1` opts out. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::process::Command; diff --git a/apps/figcraft-cli/tests/it/main.rs b/apps/figcraft-cli/tests/it/main.rs new file mode 100644 index 00000000..ae4b0488 --- /dev/null +++ b/apps/figcraft-cli/tests/it/main.rs @@ -0,0 +1,12 @@ +//! The crate's integration tests, built as one test binary. + +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod cli; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod export_depth; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod fonts; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod pdf; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod pdf_print; diff --git a/apps/figcraft-cli/tests/pdf.rs b/apps/figcraft-cli/tests/it/pdf.rs similarity index 97% rename from apps/figcraft-cli/tests/pdf.rs rename to apps/figcraft-cli/tests/it/pdf.rs index 28d5ca6c..185d5b60 100644 --- a/apps/figcraft-cli/tests/pdf.rs +++ b/apps/figcraft-cli/tests/it/pdf.rs @@ -1,5 +1,4 @@ //! `figcraft-cli export --format pdf` and `convert … .pdf` end to end. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::process::Command; diff --git a/apps/figcraft-cli/tests/pdf_print.rs b/apps/figcraft-cli/tests/it/pdf_print.rs similarity index 97% rename from apps/figcraft-cli/tests/pdf_print.rs rename to apps/figcraft-cli/tests/it/pdf_print.rs index b2ce3c9a..f12725ed 100644 --- a/apps/figcraft-cli/tests/pdf_print.rs +++ b/apps/figcraft-cli/tests/it/pdf_print.rs @@ -1,5 +1,4 @@ //! `figcraft-cli export` with PDF print options: bleed, marks, CMYK; bad lengths are usage errors. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::process::Command; diff --git a/apps/figcraft-server/tests/header_recovery.rs b/apps/figcraft-server/tests/it/header_recovery.rs similarity index 98% rename from apps/figcraft-server/tests/header_recovery.rs rename to apps/figcraft-server/tests/it/header_recovery.rs index d728908d..bb0be1d0 100644 --- a/apps/figcraft-server/tests/header_recovery.rs +++ b/apps/figcraft-server/tests/it/header_recovery.rs @@ -2,7 +2,6 @@ //! holds confirmed edits (#408): the log is replayed over the snapshot, which only the changes the //! snapshot lacks survive, and the damage is reported. A genuine leftover of a compaction cut short //! still restores silently. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use figcraft_collab::message::{Access, ClientMsg}; use figcraft_collab::{Client, Outgoing, Replica, Server}; diff --git a/apps/figcraft-server/tests/it/main.rs b/apps/figcraft-server/tests/it/main.rs new file mode 100644 index 00000000..3027ed99 --- /dev/null +++ b/apps/figcraft-server/tests/it/main.rs @@ -0,0 +1,5 @@ +//! The crate's integration tests, built as one test binary. + +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod header_recovery; +mod problem_retention; diff --git a/apps/figcraft-server/tests/problem_retention.rs b/apps/figcraft-server/tests/it/problem_retention.rs similarity index 100% rename from apps/figcraft-server/tests/problem_retention.rs rename to apps/figcraft-server/tests/it/problem_retention.rs diff --git a/crates/engine/tests/empty_text_box_undo.rs b/crates/engine/tests/it/empty_text_box_undo.rs similarity index 96% rename from crates/engine/tests/empty_text_box_undo.rs rename to crates/engine/tests/it/empty_text_box_undo.rs index ec73b83a..0a302ac2 100644 --- a/crates/engine/tests/empty_text_box_undo.rs +++ b/crates/engine/tests/it/empty_text_box_undo.rs @@ -1,5 +1,3 @@ -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] - use figcraft_engine::{ Session, doc::NodeKind, diff --git a/crates/engine/tests/library_style_acceptance.rs b/crates/engine/tests/it/library_style_acceptance.rs similarity index 97% rename from crates/engine/tests/library_style_acceptance.rs rename to crates/engine/tests/it/library_style_acceptance.rs index 233ddc8b..07940132 100644 --- a/crates/engine/tests/library_style_acceptance.rs +++ b/crates/engine/tests/it/library_style_acceptance.rs @@ -1,5 +1,4 @@ //! Accepting a library update that changes only a paint style refreshes the layers linked to it. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::disallowed_methods)] use figcraft_doc::{NodeId, StyleKind}; use figcraft_engine::Session; diff --git a/crates/engine/tests/list_indent_response.rs b/crates/engine/tests/it/list_indent_response.rs similarity index 97% rename from crates/engine/tests/list_indent_response.rs rename to crates/engine/tests/it/list_indent_response.rs index 1dae8754..e6d47956 100644 --- a/crates/engine/tests/list_indent_response.rs +++ b/crates/engine/tests/it/list_indent_response.rs @@ -1,5 +1,4 @@ //! `text.listIndent` / `text.listOutdent` report `changed` only when the document changed. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use figcraft_engine::{ Session, diff --git a/crates/engine/tests/it/main.rs b/crates/engine/tests/it/main.rs new file mode 100644 index 00000000..a97e3434 --- /dev/null +++ b/crates/engine/tests/it/main.rs @@ -0,0 +1,14 @@ +//! The crate's integration tests, built as one test binary. + +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod empty_text_box_undo; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::disallowed_methods)] +mod library_style_acceptance; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod list_indent_response; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod scope_reset; +#[allow(clippy::unwrap_used)] +mod selection_colors; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod shape_builder_response; diff --git a/crates/engine/tests/scope_reset.rs b/crates/engine/tests/it/scope_reset.rs similarity index 95% rename from crates/engine/tests/scope_reset.rs rename to crates/engine/tests/it/scope_reset.rs index 6d875d12..1838e8a9 100644 --- a/crates/engine/tests/scope_reset.rs +++ b/crates/engine/tests/it/scope_reset.rs @@ -1,5 +1,3 @@ -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] - use figcraft_engine::Session; use serde_json::json; diff --git a/crates/engine/tests/selection_colors.rs b/crates/engine/tests/it/selection_colors.rs similarity index 99% rename from crates/engine/tests/selection_colors.rs rename to crates/engine/tests/it/selection_colors.rs index e13f9f59..4e559d27 100644 --- a/crates/engine/tests/selection_colors.rs +++ b/crates/engine/tests/it/selection_colors.rs @@ -1,5 +1,3 @@ -#![allow(clippy::unwrap_used)] - use figcraft_color::Paint; use figcraft_doc::NodeId; use figcraft_engine::{ diff --git a/crates/engine/tests/shape_builder_response.rs b/crates/engine/tests/it/shape_builder_response.rs similarity index 95% rename from crates/engine/tests/shape_builder_response.rs rename to crates/engine/tests/it/shape_builder_response.rs index e1426823..6187e556 100644 --- a/crates/engine/tests/shape_builder_response.rs +++ b/crates/engine/tests/it/shape_builder_response.rs @@ -1,4 +1,3 @@ -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use figcraft_engine::Session; use serde_json::{Value, json}; diff --git a/crates/format/tests/distributed_alignment.rs b/crates/format/tests/it/distributed_alignment.rs similarity index 100% rename from crates/format/tests/distributed_alignment.rs rename to crates/format/tests/it/distributed_alignment.rs diff --git a/crates/format/tests/import_link_contract.rs b/crates/format/tests/it/import_link_contract.rs similarity index 100% rename from crates/format/tests/import_link_contract.rs rename to crates/format/tests/it/import_link_contract.rs diff --git a/crates/format/tests/it/main.rs b/crates/format/tests/it/main.rs new file mode 100644 index 00000000..6286e8db --- /dev/null +++ b/crates/format/tests/it/main.rs @@ -0,0 +1,5 @@ +//! The crate's integration tests, built as one test binary. + +mod distributed_alignment; +mod import_link_contract; +mod range_hyperlink_round_trip; diff --git a/crates/format/tests/range_hyperlink_round_trip.rs b/crates/format/tests/it/range_hyperlink_round_trip.rs similarity index 100% rename from crates/format/tests/range_hyperlink_round_trip.rs rename to crates/format/tests/it/range_hyperlink_round_trip.rs diff --git a/crates/mcp/tests/agent_tasks.rs b/crates/mcp/tests/it/agent_tasks.rs similarity index 99% rename from crates/mcp/tests/agent_tasks.rs rename to crates/mcp/tests/it/agent_tasks.rs index b35f3e7f..b83fc3b8 100644 --- a/crates/mcp/tests/agent_tasks.rs +++ b/crates/mcp/tests/it/agent_tasks.rs @@ -1,8 +1,7 @@ //! End-to-end agent tasks: an in-process MCP client completes realistic design tasks only through //! MCP tool calls, and checks every result through inspect_document / get_node like an agent would. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] -mod common; +use crate::common; use common::{Client, approx, png_dims}; use serde_json::{Value, json}; diff --git a/crates/mcp/tests/attached.rs b/crates/mcp/tests/it/attached.rs similarity index 99% rename from crates/mcp/tests/attached.rs rename to crates/mcp/tests/it/attached.rs index 69194604..f1343dd2 100644 --- a/crates/mcp/tests/attached.rs +++ b/crates/mcp/tests/it/attached.rs @@ -1,6 +1,5 @@ //! The attached backend against a fake app: a loopback control server answering with a headless //! session, speaking the desktop app's JSON-lines protocol. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::io::{BufRead, BufReader, Write}; use std::net::TcpListener; diff --git a/crates/mcp/tests/automation_roots.rs b/crates/mcp/tests/it/automation_roots.rs similarity index 98% rename from crates/mcp/tests/automation_roots.rs rename to crates/mcp/tests/it/automation_roots.rs index ced1e145..aa8e1b24 100644 --- a/crates/mcp/tests/automation_roots.rs +++ b/crates/mcp/tests/it/automation_roots.rs @@ -1,6 +1,5 @@ //! `--automation-read-root` / `--automation-write-root` over MCP (#715): a tool call reads only //! inside the read and write roots and writes only inside the write roots. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::disallowed_methods)] use std::path::PathBuf; diff --git a/crates/mcp/tests/common/mod.rs b/crates/mcp/tests/it/common/mod.rs similarity index 97% rename from crates/mcp/tests/common/mod.rs rename to crates/mcp/tests/it/common/mod.rs index be4dcea2..51e74865 100644 --- a/crates/mcp/tests/common/mod.rs +++ b/crates/mcp/tests/it/common/mod.rs @@ -1,5 +1,4 @@ //! An in-process MCP client: feeds JSON-RPC lines to `Server::handle_line`. -#![allow(dead_code, clippy::unwrap_used, clippy::expect_used, clippy::panic)] use figcraft_mcp::Server; use serde_json::{Value, json}; diff --git a/crates/mcp/tests/export_hidden_roots.rs b/crates/mcp/tests/it/export_hidden_roots.rs similarity index 96% rename from crates/mcp/tests/export_hidden_roots.rs rename to crates/mcp/tests/it/export_hidden_roots.rs index ded6f731..0a3b8de4 100644 --- a/crates/mcp/tests/export_hidden_roots.rs +++ b/crates/mcp/tests/it/export_hidden_roots.rs @@ -1,7 +1,6 @@ //! Hidden top-level layers in an export take no room in the image (issue #447). -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] -mod common; +use crate::common; use common::{Client, png_dims}; use serde_json::{Value, json}; diff --git a/crates/mcp/tests/garbage.rs b/crates/mcp/tests/it/garbage.rs similarity index 98% rename from crates/mcp/tests/garbage.rs rename to crates/mcp/tests/it/garbage.rs index 262934c7..5d9e237e 100644 --- a/crates/mcp/tests/garbage.rs +++ b/crates/mcp/tests/it/garbage.rs @@ -1,5 +1,4 @@ //! Fuzz-ish: no input line may crash the server or leave it unable to answer. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use figcraft_mcp::{Server, TOOL_NAMES}; use proptest::prelude::*; diff --git a/crates/mcp/tests/it/main.rs b/crates/mcp/tests/it/main.rs new file mode 100644 index 00000000..b5e3d89d --- /dev/null +++ b/crates/mcp/tests/it/main.rs @@ -0,0 +1,18 @@ +//! The crate's integration tests, built as one test binary. + +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod agent_tasks; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod attached; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::disallowed_methods)] +mod automation_roots; +#[allow(dead_code, clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod common; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod export_hidden_roots; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod garbage; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod protocol; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod screenshot_pixel_limit; diff --git a/crates/mcp/tests/protocol.rs b/crates/mcp/tests/it/protocol.rs similarity index 99% rename from crates/mcp/tests/protocol.rs rename to crates/mcp/tests/it/protocol.rs index 6e943a1e..617790f4 100644 --- a/crates/mcp/tests/protocol.rs +++ b/crates/mcp/tests/it/protocol.rs @@ -1,7 +1,6 @@ //! JSON-RPC / MCP protocol behaviour. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] -mod common; +use crate::common; use common::Client; use figcraft_mcp::{PROTOCOL_VERSION, Server, TOOL_NAMES}; diff --git a/crates/mcp/tests/screenshot_pixel_limit.rs b/crates/mcp/tests/it/screenshot_pixel_limit.rs similarity index 96% rename from crates/mcp/tests/screenshot_pixel_limit.rs rename to crates/mcp/tests/it/screenshot_pixel_limit.rs index 095992ff..e575f1d5 100644 --- a/crates/mcp/tests/screenshot_pixel_limit.rs +++ b/crates/mcp/tests/it/screenshot_pixel_limit.rs @@ -1,6 +1,5 @@ //! `screenshot` with `ids` must honour `maxSize` for the rendered paint area (shadows, overflow). -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] -mod common; +use crate::common; use common::{Client, png_dims}; use serde_json::{Value, json}; diff --git a/crates/ui-egui/tests/canvas_pan_release.rs b/crates/ui-egui/tests/it/canvas_pan_release.rs similarity index 98% rename from crates/ui-egui/tests/canvas_pan_release.rs rename to crates/ui-egui/tests/it/canvas_pan_release.rs index c54d20dc..cd1a6e1c 100644 --- a/crates/ui-egui/tests/canvas_pan_release.rs +++ b/crates/ui-egui/tests/it/canvas_pan_release.rs @@ -1,6 +1,5 @@ //! A canvas pan (middle button or Space + primary) ends when its button is released, even when the //! release happens over a panel: returning to the canvas with no button held must not move the view. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use egui::{Event, Key, PointerButton, Pos2, RawInput, Rect, vec2}; use figcraft_engine::Session; diff --git a/crates/ui-egui/tests/comment_open_other_page.rs b/crates/ui-egui/tests/it/comment_open_other_page.rs similarity index 100% rename from crates/ui-egui/tests/comment_open_other_page.rs rename to crates/ui-egui/tests/it/comment_open_other_page.rs diff --git a/crates/ui-egui/tests/file_menu_pdf.rs b/crates/ui-egui/tests/it/file_menu_pdf.rs similarity index 97% rename from crates/ui-egui/tests/file_menu_pdf.rs rename to crates/ui-egui/tests/it/file_menu_pdf.rs index 30b847b7..812529e0 100644 --- a/crates/ui-egui/tests/file_menu_pdf.rs +++ b/crates/ui-egui/tests/it/file_menu_pdf.rs @@ -1,6 +1,5 @@ //! File > Export frames to PDF: the menu asks where to save and writes the frames' PDF there, //! one visible top-level frame per page. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::path::PathBuf; diff --git a/crates/ui-egui/tests/guide_label_narrow.rs b/crates/ui-egui/tests/it/guide_label_narrow.rs similarity index 97% rename from crates/ui-egui/tests/guide_label_narrow.rs rename to crates/ui-egui/tests/it/guide_label_narrow.rs index 6c4276ad..464fbfed 100644 --- a/crates/ui-egui/tests/guide_label_narrow.rs +++ b/crates/ui-egui/tests/it/guide_label_narrow.rs @@ -1,5 +1,3 @@ -#![allow(clippy::unwrap_used)] - use egui::{Pos2, RawInput, Rect, Vec2, vec2}; use figcraft_engine::Session; use figcraft_ui_egui::{FigApp, NoServices}; diff --git a/crates/ui-egui/tests/it/main.rs b/crates/ui-egui/tests/it/main.rs new file mode 100644 index 00000000..007f450d --- /dev/null +++ b/crates/ui-egui/tests/it/main.rs @@ -0,0 +1,11 @@ +//! The crate's integration tests, built as one test binary. + +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod canvas_pan_release; +mod comment_open_other_page; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod file_menu_pdf; +#[allow(clippy::unwrap_used)] +mod guide_label_narrow; +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod recent_file_names; diff --git a/crates/ui-egui/tests/recent_file_names.rs b/crates/ui-egui/tests/it/recent_file_names.rs similarity index 97% rename from crates/ui-egui/tests/recent_file_names.rs rename to crates/ui-egui/tests/it/recent_file_names.rs index 461d0c73..41e37ec2 100644 --- a/crates/ui-egui/tests/recent_file_names.rs +++ b/crates/ui-egui/tests/it/recent_file_names.rs @@ -1,5 +1,4 @@ //! Recent file rows keep their full accessible name. -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use egui::{Context, Id, Pos2, RawInput, Rect, accesskit::Role, vec2}; use figcraft_engine::Session; diff --git a/docs/mcp.md b/docs/mcp.md index dfea95cc..211b98d8 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1675,7 +1675,7 @@ other key next to `$step` fails the whole batch, which is rolled back. Only an o value too) is read as a reference. A step that is itself a `command.batch` is passed on as written, so the references in its steps are to its own steps, not the outer batch's. -The end-to-end tests in `crates/mcp/tests/agent_tasks.rs` are worked examples of realistic tasks +The end-to-end tests in `crates/mcp/tests/it/agent_tasks.rs` are worked examples of realistic tasks (auto layout, a card built in one batch with step references, components and overrides, gradients and shadows, paint styles, Light/Dark variables, align/distribute/group, boolean subtract + flatten, export, undo/redo, drawing with tools). diff --git a/xtask/src/main.rs b/xtask/src/main.rs index e3f00e8b..81d48471 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,6 +1,7 @@ //! Project tasks: `cargo xtask `. //! //! - `ci` fmt check, clippy -D warnings, tests, layers, assets, wasm check +//! - `test` the workspace tests (nextest when installed) and doctests //! - `layers` crate dependency layering check //! - `assets` every file under assets/ and docs/ has a row in ATTRIBUTION.md //! - `parity` menu-catalog coverage → docs/parity-checklist.md @@ -16,7 +17,7 @@ mod icon; mod layers; -use std::process::{Command, ExitCode}; +use std::process::{Command, ExitCode, Stdio}; fn run(cmd: &mut Command) -> bool { eprintln!("$ {cmd:?}"); @@ -36,6 +37,7 @@ fn main() -> ExitCode { let task = args.first().map(String::as_str).unwrap_or("help"); let ok = match task { "ci" => ci(), + "test" => test(), "layers" => layers::check(&root()), "assets" => assets(), "parity" => parity(), @@ -45,7 +47,7 @@ fn main() -> ExitCode { "plugins" => plugins(), "bench" => bench(args.get(1).map_or("1000,10000,50000", String::as_str)), _ => { - eprintln!("tasks: ci, layers, assets, parity, version [set X.Y.Z], icon, wasm, plugins, bench [SIZES]"); + eprintln!("tasks: ci, test, layers, assets, parity, version [set X.Y.Z], icon, wasm, plugins, bench [SIZES]"); task == "help" } }; @@ -54,16 +56,31 @@ fn main() -> ExitCode { fn ci() -> bool { run(cargo().args(["fmt", "--all", "--check"])) - && run(cargo().args(["clippy", "--workspace", "--all-targets", "--", "-D", "warnings"])) - && run(cargo().args(["test", "--workspace"])) + && run(cargo().args(["clippy", "--workspace", "--all-targets", "--keep-going", "--", "-D", "warnings"])) + && test() && layers::check(&root()) && assets() && wasm() } +/// Unit and integration tests with nextest when it is installed (`cargo install cargo-nextest`), +/// else with `cargo test`; then the doctests, which nextest does not run. Examples are not built: +/// clippy's `--all-targets` already checks them. +fn test() -> bool { + let nextest = cargo().args(["nextest", "--version"]).stdout(Stdio::null()).stderr(Stdio::null()).status().is_ok_and(|s| s.success()); + let units = if nextest { + run(cargo().args(["nextest", "run", "--workspace", "--lib", "--bins", "--tests"])) + } else { + eprintln!("xtask: cargo-nextest not installed; running unit and integration tests with `cargo test`"); + run(cargo().args(["test", "--workspace", "--lib", "--bins", "--tests"])) + }; + units && run(cargo().args(["test", "--workspace", "--doc"])) +} + fn wasm() -> bool { run(cargo().args([ "check", + "--keep-going", "--target", "wasm32-unknown-unknown", "-p",