85 lines
3.1 KiB
Rust
85 lines
3.1 KiB
Rust
//! Every path that writes the IDE's graph says who wrote it (work/provenance).
|
|
//!
|
|
//! A person's edit in the IDE is theirs only if it goes through `AppState::edit`, which
|
|
//! stamps what changed ([`provenance::edit_as`](flowrs_core::graph::provenance::edit_as)).
|
|
//! A write that bypasses it — a new button that calls `state.graph.update` — would leave
|
|
//! the person's change unattributed, and so unprotected from an agent's edit. flowrs-ui is
|
|
//! wasm-only and its tests do not run with the workspace's, so the rule is held here, over
|
|
//! its source: every raw write to the graph signal carries, on one of the three lines
|
|
//! before it, a `// provenance:` comment saying why it is not a person's edit (a snapshot
|
|
//! restored, a file opened, an agent's edit already stamped, layout).
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
fn rust_files(dir: &Path, out: &mut Vec<PathBuf>) {
|
|
for e in std::fs::read_dir(dir).unwrap().flatten() {
|
|
let p = e.path();
|
|
if p.is_dir() {
|
|
rust_files(&p, out);
|
|
} else if p.extension().is_some_and(|x| x == "rs") {
|
|
out.push(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
const WRITES: &[&str] = &[
|
|
".graph.set(",
|
|
".graph.update(",
|
|
".graph.try_update(",
|
|
".graph.write(",
|
|
".graph.update_untracked(",
|
|
".graph.set_untracked(",
|
|
".graph.maybe_update(",
|
|
".graph.try_set(",
|
|
];
|
|
|
|
#[test]
|
|
#[ignore = "reads the editor's source, which is not published here"]
|
|
fn every_write_to_the_ides_graph_says_who_wrote_it() {
|
|
let ui = Path::new(env!("CARGO_MANIFEST_DIR")).join("../flowrs-ui/src");
|
|
let mut files = Vec::new();
|
|
rust_files(&ui, &mut files);
|
|
files.sort();
|
|
assert!(
|
|
files.len() > 20,
|
|
"flowrs-ui sources not found at {}",
|
|
ui.display()
|
|
);
|
|
let (mut raw, mut person, mut unexplained) = (0usize, 0usize, Vec::new());
|
|
for f in &files {
|
|
let text = std::fs::read_to_string(f).unwrap();
|
|
let lines: Vec<&str> = text.lines().collect();
|
|
for (i, l) in lines.iter().enumerate() {
|
|
let code = l.split("//").next().unwrap_or("");
|
|
person += code.matches("state.edit(").count() + code.matches("self.edit(").count();
|
|
if !WRITES.iter().any(|w| code.contains(w)) {
|
|
continue;
|
|
}
|
|
raw += 1;
|
|
let said = lines[i.saturating_sub(3)..i]
|
|
.iter()
|
|
.any(|p| p.trim_start().starts_with("// provenance:"));
|
|
if !said {
|
|
unexplained.push(format!(
|
|
"{}:{}: {}",
|
|
f.strip_prefix(&ui).unwrap().display(),
|
|
i + 1,
|
|
l.trim()
|
|
));
|
|
}
|
|
}
|
|
}
|
|
assert!(
|
|
unexplained.is_empty(),
|
|
"graph writes that neither go through AppState::edit nor say why they are not a \
|
|
person's edit (`// provenance: …` on a line before):\n{}",
|
|
unexplained.join("\n")
|
|
);
|
|
eprintln!(
|
|
"flowrs-ui: {person} person edits through AppState::edit, {raw} other writes, each explained"
|
|
);
|
|
assert!(
|
|
person >= 20,
|
|
"{person}: the person's edits no longer go through AppState::edit?"
|
|
);
|
|
}
|