mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 02:27:08 -06:00
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
This commit is contained in:
@@ -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`.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -0,0 +1,2 @@
|
||||
mod chart_native;
|
||||
mod show_clicks;
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
@@ -0,0 +1 @@
|
||||
mod decode;
|
||||
@@ -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;
|
||||
@@ -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).
|
||||
|
||||
+2
-2
@@ -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.
|
||||
|
||||
@@ -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 |
|
||||
|
||||
+2
-2
@@ -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-
|
||||
|
||||
+51
-24
@@ -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 <command>
|
||||
@@ -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<Vec<String>, 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();
|
||||
for pkg in &set {
|
||||
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", "-p", pkg]);
|
||||
let ok = run(c, &format!("cargo check --target wasm32-unknown-unknown -p {pkg}")).is_ok();
|
||||
results.push((pkg.clone(), ok));
|
||||
c.args(["check", "--target", "wasm32-unknown-unknown", "--keep-going"]);
|
||||
for pkg in &set {
|
||||
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)),
|
||||
|
||||
Reference in New Issue
Block a user