Files
benilla-octo/crates/benilla-app/tests/launcher_shape.rs
T
Sam SungandClaude Opus 5.5 8d31e9e91e A crate on top of benilla adds its own Bevy plugins through benilla_app::run_with, and a client started through it reads extended in its build line (#495)
A crate built on top of benilla now adds its own Bevy plugins through `benilla_app::run_with(build, extend)`: `extend` gets the client fully built, after the game plugins, the asset loaders and the `ExtractSchedule` executor flip, and before the probe fleet, which sees what it adds. `run` is `run_with` with nothing added, so the stock client is unchanged.

- A client started through `run_with` carries `extended` in its build id (`BuildId::summary`), so the startup banner, the crash report and the debug panel's footer all say so, and a report from an extended client reads apart from stock. The entry point sets the flag; a launcher leaves it to `..Default::default()`.
- `crates/benilla-app/examples/extended_launcher.rs` is a launcher with a plugin of its own, compiled by the gates. Its header is the shape a crate of its own copies: the manifest (benilla-app without default features and `dev` forwarded, the workspace's bevy, and the root's `[patch]` and `[profile.dev]`, which cargo reads from the root manifest only), the build script's stamp, and a `Cargo.lock` started from benilla's.
- `tests/launcher_shape.rs` holds that documented manifest to the root `Cargo.toml` and the `benilla` launcher's, so a patch or profile added later cannot leave the documented shape building a client that is not benilla's.
- `docs/CONTRIBUTING.md`: a feature 1.12.1 does not have lives in its own crate on top of benilla, started through `run_with`.

Fixes #483

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 12:05:27 +07:00

95 lines
3.3 KiB
Rust

//! The launcher `examples/extended_launcher.rs` documents for a crate on top of benilla stays in
//! step with the workspace: cargo reads `[patch]` and `[profile]` from the root manifest only, so
//! the header repeats the root's, a missing patch builds a client that is silently not benilla's,
//! and a bevy other than the workspace's is a second bevy. The rest mirrors the `benilla` launcher.
use std::path::Path;
/// A manifest by its path from this crate's root.
fn manifest(rel: &str) -> toml::Table {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join(rel);
std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("{}: {e}", path.display()))
.parse()
.unwrap_or_else(|e| panic!("{}: {e}", path.display()))
}
/// The example header's ```toml block, parsed.
fn documented() -> toml::Table {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/extended_launcher.rs");
let text = std::fs::read_to_string(&path).unwrap();
let block: Vec<&str> = text
.lines()
.map(|l| {
l.strip_prefix("//!")
.map(|l| l.strip_prefix(' ').unwrap_or(l))
})
.skip_while(|l| *l != Some("```toml"))
.skip(1)
.take_while(|l| *l != Some("```"))
.map(|l| l.expect("the ```toml block ends inside the header"))
.collect();
assert!(!block.is_empty(), "no ```toml block in {}", path.display());
block
.join("\n")
.parse()
.expect("the documented manifest parses")
}
/// `t[k1][k2]…`, or a panic naming the path.
fn at<'a>(t: &'a toml::Table, keys: &[&str]) -> &'a toml::Value {
let (first, rest) = keys.split_first().unwrap();
let mut v = t.get(*first).unwrap_or_else(|| panic!("no `{first}`"));
for k in rest {
v = v
.get(*k)
.unwrap_or_else(|| panic!("no `{}`", keys.join(".")));
}
v
}
#[test]
fn the_documented_launcher_repeats_the_root_patches_profile_and_bevy() {
let doc = documented();
let root = manifest("../../Cargo.toml");
let patched = |t: &toml::Table| -> Vec<String> {
let table = at(t, &["patch", "crates-io"]).as_table().unwrap();
table.keys().cloned().collect()
};
assert_eq!(patched(&doc), patched(&root), "[patch.crates-io]");
for keys in [
&["profile", "dev", "opt-level"][..],
&["profile", "dev", "package", "*", "opt-level"],
] {
assert_eq!(at(&doc, keys), at(&root, keys), "{}", keys.join("."));
}
assert_eq!(
at(&doc, &["dependencies", "bevy", "version"]),
at(&root, &["workspace", "dependencies", "bevy", "version"]),
"bevy's version"
);
assert_eq!(
at(&doc, &["dependencies", "bevy", "default-features"]).as_bool(),
Some(false),
"bevy adds no features"
);
}
#[test]
fn the_documented_launcher_takes_benilla_app_as_the_benilla_launcher_does() {
let doc = documented();
let shim = manifest("../benilla/Cargo.toml");
for keys in [
&["features", "dev"][..],
&["dependencies", "benilla-app", "default-features"],
] {
assert_eq!(at(&doc, keys), at(&shim, keys), "{}", keys.join("."));
}
assert!(
at(&doc, &["build-dependencies"])
.get("benilla-buildstamp")
.is_some(),
"the build script's stamp"
);
}