//! 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) { 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?" ); }