From f001f37906bfe5e91d5a684e4a57018e4066b1fc Mon Sep 17 00:00:00 2001 From: aiongg <67543387+aiongg@users.noreply.github.com> Date: Fri, 23 Oct 2026 12:43:34 -0400 Subject: [PATCH] CI: one test binary per crate, nextest, line tables only (#1213) * Build: line tables only for workspace crates, no debug info for dependencies * Tests: one integration-test binary per crate * xtask ci: nextest, doctests, test build without examples, one wasm check --- AGENTS.md | 2 +- Cargo.toml | 5 ++ apps/deckcraft-cli/tests/{ => it}/cli.rs | 0 apps/deckcraft-cli/tests/{ => it}/convert.rs | 0 apps/deckcraft-cli/tests/{ => it}/damaged.rs | 0 apps/deckcraft-cli/tests/it/main.rs | 6 ++ .../deckcraft-cli/tests/{ => it}/mcp_roots.rs | 2 - crates/engine/tests/{ => it}/chart_native.rs | 0 crates/engine/tests/it/main.rs | 2 + crates/engine/tests/{ => it}/show_clicks.rs | 0 crates/mcp/tests/{ => it}/automation_roots.rs | 2 - crates/mcp/tests/it/main.rs | 3 + crates/media/tests/{ => it}/decode.rs | 0 crates/media/tests/it/main.rs | 1 + crates/pptx/tests/{ => it}/anchor.rs | 0 crates/pptx/tests/{ => it}/chart_embed.rs | 0 crates/pptx/tests/{ => it}/comments.rs | 0 crates/pptx/tests/{ => it}/corpus.rs | 0 crates/pptx/tests/{ => it}/corpus_charts.rs | 0 crates/pptx/tests/{ => it}/corpus_elements.rs | 0 crates/pptx/tests/{ => it}/corpus_kinds.rs | 0 crates/pptx/tests/{ => it}/corpus_media.rs | 0 crates/pptx/tests/{ => it}/corpus_style.rs | 0 crates/pptx/tests/{ => it}/corpus_themes.rs | 0 crates/pptx/tests/{ => it}/fills.rs | 0 crates/pptx/tests/{ => it}/kept_parts.rs | 0 crates/pptx/tests/{ => it}/locks.rs | 0 crates/pptx/tests/it/main.rs | 27 +++++++ crates/pptx/tests/{ => it}/malformed.rs | 0 crates/pptx/tests/{ => it}/math_ns.rs | 0 crates/pptx/tests/{ => it}/notes.rs | 0 crates/pptx/tests/{ => it}/ole.rs | 0 crates/pptx/tests/{ => it}/ole_vml.rs | 0 crates/pptx/tests/{ => it}/placeholders.rs | 0 crates/pptx/tests/{ => it}/roundtrip.rs | 0 crates/pptx/tests/{ => it}/sample.rs | 0 crates/pptx/tests/{ => it}/smartart.rs | 0 crates/pptx/tests/{ => it}/sniff.rs | 0 crates/pptx/tests/{ => it}/table_styles.rs | 0 crates/pptx/tests/{ => it}/tags.rs | 0 crates/pptx/tests/{ => it}/transition_xml.rs | 0 crates/pptx/tests/{ => it}/trigger_steps.rs | 0 docs/file-format-parity.md | 6 +- docs/gaps.md | 4 +- docs/parity-checklist.md | 4 +- docs/roadmap.md | 4 +- xtask/src/main.rs | 75 +++++++++++++------ 47 files changed, 105 insertions(+), 38 deletions(-) rename apps/deckcraft-cli/tests/{ => it}/cli.rs (100%) rename apps/deckcraft-cli/tests/{ => it}/convert.rs (100%) rename apps/deckcraft-cli/tests/{ => it}/damaged.rs (100%) create mode 100644 apps/deckcraft-cli/tests/it/main.rs rename apps/deckcraft-cli/tests/{ => it}/mcp_roots.rs (97%) rename crates/engine/tests/{ => it}/chart_native.rs (100%) create mode 100644 crates/engine/tests/it/main.rs rename crates/engine/tests/{ => it}/show_clicks.rs (100%) rename crates/mcp/tests/{ => it}/automation_roots.rs (98%) create mode 100644 crates/mcp/tests/it/main.rs rename crates/media/tests/{ => it}/decode.rs (100%) create mode 100644 crates/media/tests/it/main.rs rename crates/pptx/tests/{ => it}/anchor.rs (100%) rename crates/pptx/tests/{ => it}/chart_embed.rs (100%) rename crates/pptx/tests/{ => it}/comments.rs (100%) rename crates/pptx/tests/{ => it}/corpus.rs (100%) rename crates/pptx/tests/{ => it}/corpus_charts.rs (100%) rename crates/pptx/tests/{ => it}/corpus_elements.rs (100%) rename crates/pptx/tests/{ => it}/corpus_kinds.rs (100%) rename crates/pptx/tests/{ => it}/corpus_media.rs (100%) rename crates/pptx/tests/{ => it}/corpus_style.rs (100%) rename crates/pptx/tests/{ => it}/corpus_themes.rs (100%) rename crates/pptx/tests/{ => it}/fills.rs (100%) rename crates/pptx/tests/{ => it}/kept_parts.rs (100%) rename crates/pptx/tests/{ => it}/locks.rs (100%) create mode 100644 crates/pptx/tests/it/main.rs rename crates/pptx/tests/{ => it}/malformed.rs (100%) rename crates/pptx/tests/{ => it}/math_ns.rs (100%) rename crates/pptx/tests/{ => it}/notes.rs (100%) rename crates/pptx/tests/{ => it}/ole.rs (100%) rename crates/pptx/tests/{ => it}/ole_vml.rs (100%) rename crates/pptx/tests/{ => it}/placeholders.rs (100%) rename crates/pptx/tests/{ => it}/roundtrip.rs (100%) rename crates/pptx/tests/{ => it}/sample.rs (100%) rename crates/pptx/tests/{ => it}/smartart.rs (100%) rename crates/pptx/tests/{ => it}/sniff.rs (100%) rename crates/pptx/tests/{ => it}/table_styles.rs (100%) rename crates/pptx/tests/{ => it}/tags.rs (100%) rename crates/pptx/tests/{ => it}/transition_xml.rs (100%) rename crates/pptx/tests/{ => it}/trigger_steps.rs (100%) diff --git a/AGENTS.md b/AGENTS.md index 25d12b49..8a7ce7cf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -136,7 +136,7 @@ Standard: craftrules `standards/never-crash.md`. ## 5. Quality gates (before every commit) -`cargo xtask ci` = fmt check, clippy `-D warnings`, tests, layering check, asset check, wasm +`cargo xtask ci` = fmt check, clippy `-D warnings`, tests (nextest when installed) and doctests, layering check, asset check, wasm check. Commit after each landed arc with a task id in the message (`M1.2: smart guides`) and push to `main`. diff --git a/Cargo.toml b/Cargo.toml index 1b52575f..6f50bcd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,11 +84,16 @@ self_named_constructors = "allow" large_enum_variant = "allow" result_large_err = "allow" +# Line tables keep file and line in panics and backtraces; full debug info +# for every test binary and dependency would multiply the target dir size. +# The test profile inherits both settings. [profile.dev.package."*"] opt-level = 2 +debug = false [profile.dev] opt-level = 1 +debug = "line-tables-only" [profile.release] opt-level = 3 diff --git a/apps/deckcraft-cli/tests/cli.rs b/apps/deckcraft-cli/tests/it/cli.rs similarity index 100% rename from apps/deckcraft-cli/tests/cli.rs rename to apps/deckcraft-cli/tests/it/cli.rs diff --git a/apps/deckcraft-cli/tests/convert.rs b/apps/deckcraft-cli/tests/it/convert.rs similarity index 100% rename from apps/deckcraft-cli/tests/convert.rs rename to apps/deckcraft-cli/tests/it/convert.rs diff --git a/apps/deckcraft-cli/tests/damaged.rs b/apps/deckcraft-cli/tests/it/damaged.rs similarity index 100% rename from apps/deckcraft-cli/tests/damaged.rs rename to apps/deckcraft-cli/tests/it/damaged.rs diff --git a/apps/deckcraft-cli/tests/it/main.rs b/apps/deckcraft-cli/tests/it/main.rs new file mode 100644 index 00000000..c6cdca9b --- /dev/null +++ b/apps/deckcraft-cli/tests/it/main.rs @@ -0,0 +1,6 @@ +mod cli; +mod convert; +mod damaged; +// Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md). +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod mcp_roots; diff --git a/apps/deckcraft-cli/tests/mcp_roots.rs b/apps/deckcraft-cli/tests/it/mcp_roots.rs similarity index 97% rename from apps/deckcraft-cli/tests/mcp_roots.rs rename to apps/deckcraft-cli/tests/it/mcp_roots.rs index e9e1f856..f42782c4 100644 --- a/apps/deckcraft-cli/tests/mcp_roots.rs +++ b/apps/deckcraft-cli/tests/it/mcp_roots.rs @@ -1,6 +1,4 @@ //! `deckcraft-cli mcp` with the automation root flags, run as the real binary. -// Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md). -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::io::Write; use std::path::PathBuf; diff --git a/crates/engine/tests/chart_native.rs b/crates/engine/tests/it/chart_native.rs similarity index 100% rename from crates/engine/tests/chart_native.rs rename to crates/engine/tests/it/chart_native.rs diff --git a/crates/engine/tests/it/main.rs b/crates/engine/tests/it/main.rs new file mode 100644 index 00000000..dca78f72 --- /dev/null +++ b/crates/engine/tests/it/main.rs @@ -0,0 +1,2 @@ +mod chart_native; +mod show_clicks; diff --git a/crates/engine/tests/show_clicks.rs b/crates/engine/tests/it/show_clicks.rs similarity index 100% rename from crates/engine/tests/show_clicks.rs rename to crates/engine/tests/it/show_clicks.rs 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 ed67fb3e..75229987 100644 --- a/crates/mcp/tests/automation_roots.rs +++ b/crates/mcp/tests/it/automation_roots.rs @@ -2,8 +2,6 @@ //! protocol, files open and load only from inside the read root and are saved and exported only //! inside the write root. Paths that leave a root (`..`, another folder, a sibling with the same //! prefix, a link) are refused, and nothing is written outside. -// Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md). -#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use std::path::{Path, PathBuf}; diff --git a/crates/mcp/tests/it/main.rs b/crates/mcp/tests/it/main.rs new file mode 100644 index 00000000..0314d68c --- /dev/null +++ b/crates/mcp/tests/it/main.rs @@ -0,0 +1,3 @@ +// Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md). +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod automation_roots; diff --git a/crates/media/tests/decode.rs b/crates/media/tests/it/decode.rs similarity index 100% rename from crates/media/tests/decode.rs rename to crates/media/tests/it/decode.rs diff --git a/crates/media/tests/it/main.rs b/crates/media/tests/it/main.rs new file mode 100644 index 00000000..810e1795 --- /dev/null +++ b/crates/media/tests/it/main.rs @@ -0,0 +1 @@ +mod decode; diff --git a/crates/pptx/tests/anchor.rs b/crates/pptx/tests/it/anchor.rs similarity index 100% rename from crates/pptx/tests/anchor.rs rename to crates/pptx/tests/it/anchor.rs diff --git a/crates/pptx/tests/chart_embed.rs b/crates/pptx/tests/it/chart_embed.rs similarity index 100% rename from crates/pptx/tests/chart_embed.rs rename to crates/pptx/tests/it/chart_embed.rs diff --git a/crates/pptx/tests/comments.rs b/crates/pptx/tests/it/comments.rs similarity index 100% rename from crates/pptx/tests/comments.rs rename to crates/pptx/tests/it/comments.rs diff --git a/crates/pptx/tests/corpus.rs b/crates/pptx/tests/it/corpus.rs similarity index 100% rename from crates/pptx/tests/corpus.rs rename to crates/pptx/tests/it/corpus.rs diff --git a/crates/pptx/tests/corpus_charts.rs b/crates/pptx/tests/it/corpus_charts.rs similarity index 100% rename from crates/pptx/tests/corpus_charts.rs rename to crates/pptx/tests/it/corpus_charts.rs diff --git a/crates/pptx/tests/corpus_elements.rs b/crates/pptx/tests/it/corpus_elements.rs similarity index 100% rename from crates/pptx/tests/corpus_elements.rs rename to crates/pptx/tests/it/corpus_elements.rs diff --git a/crates/pptx/tests/corpus_kinds.rs b/crates/pptx/tests/it/corpus_kinds.rs similarity index 100% rename from crates/pptx/tests/corpus_kinds.rs rename to crates/pptx/tests/it/corpus_kinds.rs diff --git a/crates/pptx/tests/corpus_media.rs b/crates/pptx/tests/it/corpus_media.rs similarity index 100% rename from crates/pptx/tests/corpus_media.rs rename to crates/pptx/tests/it/corpus_media.rs diff --git a/crates/pptx/tests/corpus_style.rs b/crates/pptx/tests/it/corpus_style.rs similarity index 100% rename from crates/pptx/tests/corpus_style.rs rename to crates/pptx/tests/it/corpus_style.rs diff --git a/crates/pptx/tests/corpus_themes.rs b/crates/pptx/tests/it/corpus_themes.rs similarity index 100% rename from crates/pptx/tests/corpus_themes.rs rename to crates/pptx/tests/it/corpus_themes.rs diff --git a/crates/pptx/tests/fills.rs b/crates/pptx/tests/it/fills.rs similarity index 100% rename from crates/pptx/tests/fills.rs rename to crates/pptx/tests/it/fills.rs diff --git a/crates/pptx/tests/kept_parts.rs b/crates/pptx/tests/it/kept_parts.rs similarity index 100% rename from crates/pptx/tests/kept_parts.rs rename to crates/pptx/tests/it/kept_parts.rs diff --git a/crates/pptx/tests/locks.rs b/crates/pptx/tests/it/locks.rs similarity index 100% rename from crates/pptx/tests/locks.rs rename to crates/pptx/tests/it/locks.rs diff --git a/crates/pptx/tests/it/main.rs b/crates/pptx/tests/it/main.rs new file mode 100644 index 00000000..228beb3a --- /dev/null +++ b/crates/pptx/tests/it/main.rs @@ -0,0 +1,27 @@ +mod anchor; +mod chart_embed; +mod comments; +mod corpus; +mod corpus_charts; +mod corpus_elements; +mod corpus_kinds; +mod corpus_media; +mod corpus_style; +mod corpus_themes; +mod fills; +mod kept_parts; +mod locks; +mod malformed; +mod math_ns; +mod notes; +mod ole; +mod ole_vml; +mod placeholders; +mod roundtrip; +mod sample; +mod smartart; +mod sniff; +mod table_styles; +mod tags; +mod transition_xml; +mod trigger_steps; diff --git a/crates/pptx/tests/malformed.rs b/crates/pptx/tests/it/malformed.rs similarity index 100% rename from crates/pptx/tests/malformed.rs rename to crates/pptx/tests/it/malformed.rs diff --git a/crates/pptx/tests/math_ns.rs b/crates/pptx/tests/it/math_ns.rs similarity index 100% rename from crates/pptx/tests/math_ns.rs rename to crates/pptx/tests/it/math_ns.rs diff --git a/crates/pptx/tests/notes.rs b/crates/pptx/tests/it/notes.rs similarity index 100% rename from crates/pptx/tests/notes.rs rename to crates/pptx/tests/it/notes.rs diff --git a/crates/pptx/tests/ole.rs b/crates/pptx/tests/it/ole.rs similarity index 100% rename from crates/pptx/tests/ole.rs rename to crates/pptx/tests/it/ole.rs diff --git a/crates/pptx/tests/ole_vml.rs b/crates/pptx/tests/it/ole_vml.rs similarity index 100% rename from crates/pptx/tests/ole_vml.rs rename to crates/pptx/tests/it/ole_vml.rs diff --git a/crates/pptx/tests/placeholders.rs b/crates/pptx/tests/it/placeholders.rs similarity index 100% rename from crates/pptx/tests/placeholders.rs rename to crates/pptx/tests/it/placeholders.rs diff --git a/crates/pptx/tests/roundtrip.rs b/crates/pptx/tests/it/roundtrip.rs similarity index 100% rename from crates/pptx/tests/roundtrip.rs rename to crates/pptx/tests/it/roundtrip.rs diff --git a/crates/pptx/tests/sample.rs b/crates/pptx/tests/it/sample.rs similarity index 100% rename from crates/pptx/tests/sample.rs rename to crates/pptx/tests/it/sample.rs diff --git a/crates/pptx/tests/smartart.rs b/crates/pptx/tests/it/smartart.rs similarity index 100% rename from crates/pptx/tests/smartart.rs rename to crates/pptx/tests/it/smartart.rs diff --git a/crates/pptx/tests/sniff.rs b/crates/pptx/tests/it/sniff.rs similarity index 100% rename from crates/pptx/tests/sniff.rs rename to crates/pptx/tests/it/sniff.rs diff --git a/crates/pptx/tests/table_styles.rs b/crates/pptx/tests/it/table_styles.rs similarity index 100% rename from crates/pptx/tests/table_styles.rs rename to crates/pptx/tests/it/table_styles.rs diff --git a/crates/pptx/tests/tags.rs b/crates/pptx/tests/it/tags.rs similarity index 100% rename from crates/pptx/tests/tags.rs rename to crates/pptx/tests/it/tags.rs diff --git a/crates/pptx/tests/transition_xml.rs b/crates/pptx/tests/it/transition_xml.rs similarity index 100% rename from crates/pptx/tests/transition_xml.rs rename to crates/pptx/tests/it/transition_xml.rs diff --git a/crates/pptx/tests/trigger_steps.rs b/crates/pptx/tests/it/trigger_steps.rs similarity index 100% rename from crates/pptx/tests/trigger_steps.rs rename to crates/pptx/tests/it/trigger_steps.rs diff --git a/docs/file-format-parity.md b/docs/file-format-parity.md index 87a36322..d5f67246 100644 --- a/docs/file-format-parity.md +++ b/docs/file-format-parity.md @@ -16,7 +16,7 @@ PowerPoint opens and saves; Viewer = opens only). | Format | PowerPoint | DeckCraft read | DeckCraft write | Fidelity / notes | Tested by | |---|---|---|---|---|---| -| `.pptx` presentation | Editor | yes | yes | Broad (see below); an owned corpus of decks we author round-trips tables, charts, animations, media, sections, masters and layouts, comments, links and actions, custom shows, rotated groups, inherited placeholders, text effects and body layout, theme effects, fills, bevels, connectors, 3-D models and animation bounce end. Not measured against PowerPoint renders or decks from outside this repo | `crates/pptx/tests/corpus.rs`, `corpus_kinds.rs`, `corpus_elements.rs`, `corpus_style.rs`, `corpus_themes.rs`, `corpus_charts.rs`, `corpus_media.rs`, `roundtrip.rs`, `sample.rs`, `malformed.rs`, `sniff.rs`; opened in PowerPoint by hand 2026-10-06 | +| `.pptx` presentation | Editor | yes | yes | Broad (see below); an owned corpus of decks we author round-trips tables, charts, animations, media, sections, masters and layouts, comments, links and actions, custom shows, rotated groups, inherited placeholders, text effects and body layout, theme effects, fills, bevels, connectors, 3-D models and animation bounce end. Not measured against PowerPoint renders or decks from outside this repo | `crates/pptx/tests/it/corpus.rs`, `corpus_kinds.rs`, `corpus_elements.rs`, `corpus_style.rs`, `corpus_themes.rs`, `corpus_charts.rs`, `corpus_media.rs`, `roundtrip.rs`, `sample.rs`, `malformed.rs`, `sniff.rs`; opened in PowerPoint by hand 2026-10-06 | | `.potx` template | Editor | yes (as a presentation) | no: written with the `.pptx` content type | `file.saveTemplate` is Save As under another name | none | | `.ppsx` slide show | Editor | yes (as a presentation) | no: written as `.pptx` content | Handed over by the system (command line, file association) it starts the slide show, as in PowerPoint; File › Open opens it for editing. The macOS Finder event arrives with #432 | `crates/ui-egui/src/opening.rs` tests | | `.pptm` / `.potm` / `.ppsm` macro-enabled | Editor | no | no | Should open and keep `vbaProject.bin` without running it | none | @@ -77,7 +77,7 @@ the round trip even though DeckCraft doesn't model it. | Presentation, slide size, sections (p14), custom shows | yes | yes | | | Slide masters, layouts, placeholders and inheritance | yes | yes | | | Themes: colour, font (Latin/EA/CS), effect schemes, background styles | yes | yes | Unknown theme parts kept | -| Notes slides and notes master | yes | yes | Header, footer, date and slide-number text on the notes master is kept. Edited in View ▸ Notes Master. Notes keep their run and paragraph formatting (bold, italic, underline, size, levels, indents, bullets), shown and kept when edited in the notes pane and Notes Page (`crates/pptx/tests/notes.rs`). PDF notes pages print them as plain text; levels and bullets inherited from a custom notes master aren't shown | +| Notes slides and notes master | yes | yes | Header, footer, date and slide-number text on the notes master is kept. Edited in View ▸ Notes Master. Notes keep their run and paragraph formatting (bold, italic, underline, size, levels, indents, bullets), shown and kept when edited in the notes pane and Notes Page (`crates/pptx/tests/it/notes.rs`). PDF notes pages print them as plain text; levels and bullets inherited from a custom notes master aren't shown | | Handout master | yes | yes | Header, footer, date and slide-number text is kept. Edited in View ▸ Handout Master | | Shapes: preset geometry (~180 presets), custom geometry, groups, connectors | yes | yes | Presets re-derived in `crates/geom/src/preset.rs` (and `preset/extra.rs`). Outlines, dashes, arrowheads and ink inside a group, and text, keep their size in points whatever the group's child-coordinate scale (#233). | | Fills: solid, gradient, picture (stretch/tile/crop), pattern, group | yes | yes | | @@ -108,7 +108,7 @@ the round trip even though DeckCraft doesn't model it. ### What would move the PPTX number 1. A larger owned corpus (corporate templates, SmartArt, chartex charts, EMF, embedded fonts, - every transition and animation) in a corpus repo. `crates/pptx/tests/corpus.rs` and + every transition and animation) in a corpus repo. `crates/pptx/tests/it/corpus.rs` and `corpus_kinds.rs` already check open → save → reopen (parts and text) for decks we author: tables, charts, animations, media, sections and masters/layouts among them. Still needed: render checks and a PowerPoint reference render for each (owner runs PowerPoint). diff --git a/docs/gaps.md b/docs/gaps.md index 57271c4e..b9d0f16f 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -181,7 +181,7 @@ Detail in [file-format-parity.md](file-format-parity.md). `Series.secondary_axis`) and is not written back when the chart is rebuilt. An unchanged chart's embedded workbook now survives save (#335); editing the chart still drops it rather than writing a stale spreadsheet. The workbook and other retained chart parts - also survive `.deckcraft` save/reopen (`crates/engine/tests/chart_native.rs`), with binary + also survive `.deckcraft` save/reopen (`crates/engine/tests/it/chart_native.rs`), with binary payloads in bounded ZIP entries sharing the media load budget (`crates/format` tests). - **Impact:** most business decks have charts; editing their data is routine. - **Estimate:** 12–20 h. Data and elements are **beta blockers** (6–10 h). @@ -215,7 +215,7 @@ of the effect gallery. Detail in [animation-parity.md](animation-parity.md). 8 shapes in two decks) does nothing; triggers that start on `onStopAudio` or `begin` conditions are not read as triggers; click boxes are the shape's bounding box (a hexagon's corners count) and do not follow a shape that a motion path has moved. Trigger sequences now keep their separate - click steps on PPTX save, including paragraph builds (`crates/pptx/tests/trigger_steps.rs`). + click steps on PPTX save, including paragraph builds (`crates/pptx/tests/it/trigger_steps.rs`). - **Impact:** games built around sound effects on buttons, audio-triggered effects or moving clickable shapes do not play as authored. - **Estimate:** 4–8 h. diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index f83835d3..3a5c51b9 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -54,7 +54,7 @@ Open P0 items: Contextual tabs (Shape Format, Picture Format, Table Design/Layou | Application shell | Multiple open presentations | P1 | P | | Application shell | Preferences (autosave, units, defaults) | P2 | P | | Files | New blank presentation | P0 | D | -| Files | Native file format (open/save; chart package parts retained, `crates/engine/tests/chart_native.rs`) | P0 | D | +| Files | Native file format (open/save; chart package parts retained, `crates/engine/tests/it/chart_native.rs`) | P0 | D | | Files | Open PowerPoint .pptx | P0 | D | | Files | Save as PowerPoint .pptx | P0 | D | | Files | Open/save .potx/.ppsx/.pptm variants (.potx/.ppsx open; saved with the .pptx content type; no .pptm) | P2 | P | @@ -206,7 +206,7 @@ Open P0 items: Contextual tabs (Shape Format, Picture Format, Table Design/Layou | Animations | Effect options, start (on click/with/after), duration, delay | P0 | D | | Animations | Animation pane (reorder, timing) | P0 | P | | Animations | By-paragraph text builds | P1 | D | -| Animations | Triggers (separate click steps and paragraph builds round-trip; `crates/pptx/tests/trigger_steps.rs`) | P2 | D | +| Animations | Triggers (separate click steps and paragraph builds round-trip; `crates/pptx/tests/it/trigger_steps.rs`) | P2 | D | | Animations | Animation Painter | P2 | D | | Animations | Preview in editor | P1 | D | | Slide show | Full-screen show from start / current | P0 | D | diff --git a/docs/roadmap.md b/docs/roadmap.md index 235b44ae..f3f92ef2 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -15,7 +15,7 @@ points and lead the beta plan. | Core workflow | Works end to end? | Evidence | Hours to full pass | |---|---|---|---| -| Build a deck from scratch (theme, layouts, titles and bullets, shapes, pictures from file), save, close and reopen it | yes | Commands for all of it; `.deckcraft` and `.pptx` round-trip tests (`crates/pptx/tests/roundtrip.rs`, `crates/format`); AutoRecover. Close discards edits without asking (#60, PR #75); image *paste* fails on Windows/Linux (#53), though insert-from-file works | 1–3 | +| Build a deck from scratch (theme, layouts, titles and bullets, shapes, pictures from file), save, close and reopen it | yes | Commands for all of it; `.deckcraft` and `.pptx` round-trip tests (`crates/pptx/tests/it/roundtrip.rs`, `crates/format`); AutoRecover. Close discards edits without asking (#60, PR #75); image *paste* fails on Windows/Linux (#53), though insert-from-file works | 1–3 | | Open a colleague's `.pptx`, edit it, save it back as `.pptx` that PowerPoint opens | partial (not blocking) | The reader is lenient and keeps unknown objects. Files open in PowerPoint without repair (checked 2026-10-06). But only generated decks have been tested; text inside EMF/WMF pictures is missing; comment threads, media options and rewind are lost (#70, #74, #77) | 31–55 | | Present: full-screen show with transitions, animations, media, presenter view with notes, next slide and timer | yes | 48/48 transitions, 64 effects, triggers, builds, media playback, presenter window, See All Slides and zoom. The presenter timer pauses and resets, and notes have a size control. A custom show plays only its slides. Typing a slide number during the show shows it, and Enter goes there. Presenter view isn't placed on the second display automatically (drag it there; #433) | 2–4 | | Add business content: tables, charts with their data, simple diagrams | partial (not blocking) | Tables with styles, merge/split, all D or P. Charts insert with the common types and edit data in the Chart Data dialog (P0 partial); SmartArt is basic (pre-drawn shapes) | 12–20 | @@ -26,7 +26,7 @@ points and lead the beta plan. 1. **Stop losing work and crashing:** land Close's save prompt (#60, PR #75), the Windows GPU startup crashes (#40, #59), image paste on Windows/Linux (#53). 6–12 h. -2. **PPTX on real decks:** the owned corpus (`crates/pptx/tests/corpus*.rs`) round-trips decks we +2. **PPTX on real decks:** the owned corpus (`crates/pptx/tests/it/corpus*.rs`) round-trips decks we author: tables, charts, animations, media, sections, masters and layouts, comments, links and actions, custom shows, rotated groups, inherited placeholders, text effects and body layout, theme effects, fills, bevels, connectors, 3-D models and animation bounce end, and keeps notes- diff --git a/xtask/src/main.rs b/xtask/src/main.rs index edb1331e..632769fb 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -13,7 +13,7 @@ mod stats; mod version; use std::path::{Path, PathBuf}; -use std::process::{Command, ExitCode}; +use std::process::{Command, ExitCode, Stdio}; const USAGE: &str = "\ usage: cargo xtask @@ -22,8 +22,10 @@ commands: assets check that every icon/image/font/asset is attributed in ATTRIBUTION.md pdf-deps verify pinned writer sources and the production feature boundary layers enforce the crate dependency layering (plan/architecture.md §3) - wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates - ci fmt --check, pdf-deps, clippy -D warnings, test, assets, layers, wasm (stops at first failure) + wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates (one call) + test workspace tests (cargo nextest when installed, else cargo test), then doctests + ci fmt --check, pdf-deps, clippy -D warnings, test, doctest, assets, layers, wasm + (stops at first failure) stats [--exact] count tests and lines per crate (--exact: ask the test harness via `-- --list`) bench [--save] [DECK...] time open, render, save and export of the sample (and DECKs) in release, and @@ -41,6 +43,7 @@ fn main() -> ExitCode { Some("layers") => cmd_layers(), Some("pdf-deps") => pdf_deps::run(&root()), Some("wasm") => cmd_wasm(), + Some("test") => cmd_test().and_then(|()| cmd_doctest()), Some("ci") => cmd_ci(), Some("stats") => stats::run(&root(), rest.contains(&"--exact")), Some("parity") => parity::run(&root()), @@ -136,21 +139,51 @@ fn wasm_set() -> Result, String> { .collect()) } +/// One `cargo check` for the whole set: each crate is checked once, and +/// `--keep-going` still reports every failing crate. Features unify across the +/// set, so each crate is checked with the union of the features the set enables. fn cmd_wasm() -> Result<(), String> { let set = wasm_set()?; - let mut results = Vec::new(); + if set.is_empty() { + return Err("no wasm-safe crates found in the workspace metadata".into()); + } + let mut c = cargo(); + c.args(["check", "--target", "wasm32-unknown-unknown", "--keep-going"]); for pkg in &set { - let mut c = cargo(); - c.args(["check", "--target", "wasm32-unknown-unknown", "-p", pkg]); - let ok = run(c, &format!("cargo check --target wasm32-unknown-unknown -p {pkg}")).is_ok(); - results.push((pkg.clone(), ok)); + c.args(["-p", pkg]); } - println!("\nwasm32-unknown-unknown check:"); - for (p, ok) in &results { - println!(" {:<6} {p}", if *ok { "ok" } else { "FAIL" }); - } - let failed = results.iter().filter(|r| !r.1).count(); - if failed == 0 { Ok(()) } else { Err(format!("{failed} crate(s) failed the wasm check")) } + run(c, &format!("cargo check --target wasm32-unknown-unknown --keep-going -p {}", set.join(" -p ")))?; + println!("\nwasm32-unknown-unknown check: ok ({} crates: {})", set.len(), set.join(", ")); + Ok(()) +} + +/// Test targets for the test build. Examples are left out so they aren't +/// linked; clippy `--all-targets` still compiles them. +const TEST_TARGETS: [&str; 4] = ["--workspace", "--lib", "--bins", "--tests"]; + +fn nextest_available() -> bool { + cargo().args(["nextest", "--version"]).stdout(Stdio::null()).stderr(Stdio::null()).status().is_ok_and(|s| s.success()) +} + +fn cmd_test() -> Result<(), String> { + let mut c = cargo(); + let tool = if nextest_available() { + c.args(["nextest", "run"]); + "nextest run" + } else { + eprintln!("note: cargo-nextest is not installed, running cargo test (cargo install cargo-nextest --locked)"); + c.arg("test"); + "test" + }; + c.args(TEST_TARGETS); + run(c, &format!("cargo {tool} {}", TEST_TARGETS.join(" "))) +} + +/// nextest does not run doctests. +fn cmd_doctest() -> Result<(), String> { + let mut c = cargo(); + c.args(["test", "--workspace", "--doc"]); + run(c, "cargo test --workspace --doc") } fn cmd_ci() -> Result<(), String> { @@ -169,18 +202,12 @@ fn cmd_ci() -> Result<(), String> { "clippy", Box::new(|| { let mut c = cargo(); - c.args(["clippy", "--workspace", "--all-targets", "--", "-D", "warnings"]); - run(c, "cargo clippy --workspace --all-targets -- -D warnings") - }), - ), - ( - "test", - Box::new(|| { - let mut c = cargo(); - c.args(["test", "--workspace"]); - run(c, "cargo test --workspace") + c.args(["clippy", "--workspace", "--all-targets", "--keep-going", "--", "-D", "warnings"]); + run(c, "cargo clippy --workspace --all-targets --keep-going -- -D warnings") }), ), + ("test", Box::new(cmd_test)), + ("doctest", Box::new(cmd_doctest)), ("assets", Box::new(|| assets::run(&root()))), ("layers", Box::new(cmd_layers)), ("wasm", Box::new(cmd_wasm)),