flowrs-engine/crates/flowrs-core/tests/palette_reach.rs
flowRS fd958c0547 flowRS engine, cut from flowRS 3451b065
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 19:04:39 -05:00

74 lines
2.6 KiB
Rust

//! Every widget the registry knows must be listed in the node catalog.
//!
//! The editor's palette is built from `init_node_types()`. A widget that exists in
//! `WidgetRegistry` but has no catalog entry is real, executes, generates code — and
//! cannot be found by a person using the tool. It is the same gap that had the instrument
//! catalogue, the forge, energy metering and dialect import reachable by an agent and by
//! nobody else, one level further in.
use flowrs_core::graph::nodes::init_node_types;
use flowrs_core::graph::widget::WidgetRegistry;
use std::collections::HashSet;
#[test]
fn every_registry_widget_is_in_the_palette() {
let catalog: HashSet<String> = init_node_types().iter().map(|n| n.name.clone()).collect();
let reg = WidgetRegistry::with_builtins();
// A comparison between two empty sets passes and proves nothing; several guards in
// this repo have done exactly that. Pin that both sides are populated.
assert!(
catalog.len() > 200,
"catalog looks empty: {}",
catalog.len()
);
assert!(
reg.all().len() > 100,
"registry looks empty: {}",
reg.all().len()
);
let missing: Vec<String> = reg
.all()
.iter()
.map(|w| w.id())
.filter(|id| !catalog.contains(id))
.collect();
assert!(
missing.is_empty(),
"{} widget(s) exist and cannot be found in the palette:\n {}",
missing.len(),
missing.join("\n ")
);
}
/// And the other direction: a catalog entry with no widget and no primitive behind it
/// would be a palette tile that produces a node nothing can run or emit.
#[test]
fn every_palette_entry_has_something_behind_it() {
let reg = WidgetRegistry::with_builtins();
let orphans: Vec<String> = init_node_types()
.iter()
.filter(|n| reg.get(&n.name).is_none())
// Primitives are implemented in codegen rather than the registry; `node_coverage`
// is what proves those emit, so an entry is only an orphan if neither knows it.
.filter(|n| {
let mut g = flowrs_core::graph::Graph::new();
g.add_node(&n.name, 0.0, 0.0);
match g.to_rust() {
Ok(src) => src.contains(&format!("// TODO: unsupported node type `{}`", n.name)),
Err(e) => {
!e.contains("is not connected") && !e.contains("only valid inside a loop")
}
}
})
.map(|n| n.name.clone())
.collect();
assert!(
orphans.is_empty(),
"{} palette entries have no widget and emit nothing:\n {}",
orphans.len(),
orphans.join("\n ")
);
}