GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
tests/doc_claims.rs (11.9K)
1 //! CLAUDE.md, checked against the crate it describes.
2 //!
3 //! An integration test on purpose: anything under `src/` would be counted by
4 //! its own scans — a `#[cfg(test)]` block added here to measure which modules
5 //! carry tests promptly made this module one of them, and the line-count
6 //! figures would drift by however long this file happens to be.
7 //!
8 //! Deliberately MIRRORED per crate rather than shared from a helper: each is
9 //! its own git repository that must build standalone, and this needs nothing
10 //! but std.
11
12 /// CLAUDE.md's `(~Nk lines)` figures, checked against the files they describe.
13 ///
14 /// Those numbers exist to set expectations before opening a file — "this is
15 /// the big one" — and they drift in total silence, because a stale number
16 /// reads exactly like a fresh one. A workspace sweep on 2026-09-19 found
17 /// EVERY size figure in every CLAUDE.md stale, all of them undercounts, the
18 /// worst by 49% (cce-designer's app.rs, written ~5.4k at 8046 lines).
19 ///
20 /// Tolerance is 10%: loose enough that ordinary work does not trip it, tight
21 /// enough that a file cannot quietly double. When it fails, write the number
22 /// it reports — that is the whole fix.
23 ///
24 /// Deliberately MIRRORED into each crate that carries such a figure rather
25 /// than shared from a helper: every crate here is its own git repository and
26 /// must build standalone, and this needs nothing but `std`. Same call
27 /// `ramp.rs` makes about its cce-ui parser.
28 pub mod size_claims {
29 use std::path::{Path, PathBuf};
30
31 /// One `(~Nk lines)` claim: the name as CLAUDE.md spells it, the figure,
32 /// and whether the claim also calls it the largest file.
33 fn claims(doc: &str) -> Vec<(String, f64, bool)> {
34 const TAIL: &str = " lines)";
35 let mut out = Vec::new();
36 let mut i = 0;
37 while let Some(p) = doc[i..].find(TAIL) {
38 let end = i + p;
39 i = end + TAIL.len();
40 let Some(open) = doc[..end].rfind('(') else { continue };
41 let inner = &doc[open + 1..end];
42 // "~8k", or "largest file, ~6.9k" — take the last word.
43 let largest = inner.contains("largest file");
44 let word = inner.rsplit([' ', ',']).next().unwrap_or("").trim();
45 let digits = word.trim_start_matches('~');
46 let value = match digits.strip_suffix('k') {
47 Some(k) => k.parse::<f64>().ok().map(|v| v * 1000.0),
48 None => digits.parse::<f64>().ok(),
49 };
50 // The backticked name immediately before the parenthetical.
51 let before = &doc[..open];
52 let name = before.rfind('`').and_then(|e| {
53 before[..e].rfind('`').map(|s| before[s + 1..e].to_string())
54 });
55 if let (Some(v), Some(n)) = (value, name) {
56 if v > 0.0 {
57 out.push((n, v, largest));
58 }
59 }
60 }
61 out
62 }
63
64 /// Every `.rs` file under `src/`, as (path, line count).
65 fn sources(root: &Path) -> Vec<(PathBuf, usize)> {
66 fn walk(dir: &Path, out: &mut Vec<(PathBuf, usize)>) {
67 let Ok(entries) = std::fs::read_dir(dir) else { return };
68 for e in entries.flatten() {
69 let p = e.path();
70 if p.is_dir() {
71 walk(&p, out);
72 } else if p.extension().and_then(|x| x.to_str()) == Some("rs") {
73 if let Ok(s) = std::fs::read_to_string(&p) {
74 out.push((p, s.lines().count()));
75 }
76 }
77 }
78 }
79 let mut v = Vec::new();
80 walk(&root.join("src"), &mut v);
81 v
82 }
83
84 #[test]
85 fn test_claude_md_line_counts_match_the_source() {
86 let root = Path::new(env!("CARGO_MANIFEST_DIR"));
87 let doc = std::fs::read_to_string(root.join("CLAUDE.md"))
88 .expect("CLAUDE.md is missing next to Cargo.toml");
89 let files = sources(root);
90 let claims = claims(&doc);
91 assert!(
92 !claims.is_empty(),
93 "no `(~N lines)` figure found in CLAUDE.md — either the syntax changed \
94 and this scan needs updating, or the figures were removed and so \
95 should this test"
96 );
97
98 let mut bad: Vec<String> = Vec::new();
99 for (name, claimed, largest) in &claims {
100 // A path relative to the crate root, else a unique basename.
101 let hits: Vec<&(PathBuf, usize)> = if root.join(name).is_file() {
102 files.iter().filter(|(p, _)| *p == root.join(name)).collect()
103 } else {
104 files
105 .iter()
106 .filter(|(p, _)| p.file_name().and_then(|x| x.to_str()) == Some(name.as_str()))
107 .collect()
108 };
109 let [(path, actual)] = hits[..] else {
110 bad.push(format!("`{name}`: names {} files under src/, cannot check", hits.len()));
111 continue;
112 };
113 let actual = *actual as f64;
114 let drift = (actual - claimed) / claimed;
115 if drift.abs() > 0.10 {
116 bad.push(format!(
117 "`{name}` is documented as ~{} lines but has {} ({:+.0}%) — write ~{}",
118 round_k(*claimed),
119 actual as usize,
120 drift * 100.0,
121 round_k(actual)
122 ));
123 }
124 if *largest {
125 if let Some((big, n)) = files.iter().max_by_key(|(_, n)| *n) {
126 if big != path {
127 bad.push(format!(
128 "`{name}` is called the largest file, but {} has {n} lines",
129 big.strip_prefix(root).unwrap_or(big).display()
130 ));
131 }
132 }
133 }
134 }
135 assert!(bad.is_empty(), "CLAUDE.md size claims are stale:\n {}", bad.join("\n "));
136 }
137
138 /// "~8k" for 8046, "~3.1k" for 3134, "~950" for 950 — the spelling the
139 /// docs already use, so the failure message can be pasted straight in.
140 fn round_k(n: f64) -> String {
141 if n < 1000.0 {
142 return format!("{}", n.round() as usize);
143 }
144 let k = n / 1000.0;
145 if (k - k.round()).abs() < 0.05 {
146 format!("{}k", k.round() as usize)
147 } else {
148 format!("{k:.1}k")
149 }
150 }
151 }
152
153 /// CLAUDE.md's NAMES, checked against the crate: the tests it cites as the
154 /// proof of a claim, and the source paths it points at.
155 ///
156 /// The line counts above were the only check until 2026-10-08, when an audit
157 /// found a test cited by a name it no longer had, a constant cited by a name
158 /// it never had, `layout.rs` called the largest file after it had become a
159 /// directory, and claims about a `build.rs` that existed and `view*` methods
160 /// that did not — every one reading exactly like a true statement. A name
161 /// that is meant to be CURRENT is checkable; history ("until 2026-10-02 it
162 /// was…") names things on purpose that are gone, so only these two
163 /// unambiguous kinds are checked.
164 pub mod name_claims {
165 use std::collections::HashSet;
166 use std::path::Path;
167
168 fn doc() -> String {
169 std::fs::read_to_string(Path::new(env!("CARGO_MANIFEST_DIR")).join("CLAUDE.md"))
170 .expect("CLAUDE.md is missing next to Cargo.toml")
171 }
172
173 fn rust_files(dir: &Path, out: &mut Vec<String>) {
174 let Ok(entries) = std::fs::read_dir(dir) else { return };
175 for e in entries.flatten() {
176 let p = e.path();
177 if p.is_dir() {
178 rust_files(&p, out);
179 } else if p.extension().and_then(|x| x.to_str()) == Some("rs") {
180 if let Ok(s) = std::fs::read_to_string(&p) {
181 out.push(s);
182 }
183 }
184 }
185 }
186
187 /// Every `fn` name defined under src/, tests/ and examples/.
188 fn defined_fns() -> HashSet<String> {
189 let root = Path::new(env!("CARGO_MANIFEST_DIR"));
190 let mut texts = Vec::new();
191 for d in ["src", "tests", "examples"] {
192 rust_files(&root.join(d), &mut texts);
193 }
194 let mut names = HashSet::new();
195 for t in &texts {
196 let mut rest = t.as_str();
197 while let Some(i) = rest.find("fn ") {
198 let after = &rest[i + 3..];
199 let name: String = after.chars().take_while(|c| c.is_alphanumeric() || *c == '_').collect();
200 if !name.is_empty() {
201 names.insert(name);
202 }
203 rest = after;
204 }
205 }
206 names
207 }
208
209 /// The backticked snake_case identifiers in the sentence that ends at
210 /// `end` (exclusive): from the previous sentence break to there.
211 fn identifiers_before(doc: &str, end: usize) -> Vec<String> {
212 let head = &doc[..end];
213 let start = [". ", ".\n", "\n\n", ": "]
214 .iter()
215 .filter_map(|b| head.rfind(b).map(|i| i + b.len()))
216 .max()
217 .unwrap_or(0);
218 let sentence = &head[start..];
219 sentence
220 .split('`')
221 .skip(1)
222 .step_by(2)
223 .filter(|t| {
224 t.contains('_')
225 && t.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
226 })
227 .map(str::to_string)
228 .collect()
229 }
230
231 /// "`a_toggle_is_a_field_whose_run_glides` is the test", "`x` and `y` are
232 /// the tests": each one names a function that exists.
233 #[test]
234 fn test_the_tests_claude_md_cites_exist() {
235 let doc = doc();
236 let fns = defined_fns();
237 let mut cited = 0;
238 let mut bad = Vec::new();
239 for phrase in [" is the test", " are the tests"] {
240 for (at, _) in doc.match_indices(phrase) {
241 for name in identifiers_before(&doc, at) {
242 cited += 1;
243 if !fns.contains(&name) {
244 bad.push(format!("`{name}` is cited as a test, and no such fn exists"));
245 }
246 }
247 }
248 }
249 assert!(cited > 0, "no `… is the test` citation found — did the phrasing change?");
250 assert!(bad.is_empty(), "CLAUDE.md cites tests that do not exist:\n {}", bad.join("\n "));
251 }
252
253 /// A backticked path into this crate's source tree — `src/…`, or one that
254 /// starts with a directory under src/ (`backend/text.rs`, `widget/`) —
255 /// exists. Bare file names are left alone: `osk.rs` is the compositor's.
256 #[test]
257 fn test_the_source_paths_claude_md_names_exist() {
258 let root = Path::new(env!("CARGO_MANIFEST_DIR"));
259 let src_dirs: HashSet<String> = std::fs::read_dir(root.join("src"))
260 .expect("src/")
261 .flatten()
262 .filter(|e| e.path().is_dir())
263 .map(|e| e.file_name().to_string_lossy().into_owned())
264 .collect();
265 let doc = doc();
266 let mut bad = Vec::new();
267 let mut checked = 0;
268 for token in doc.split('`').skip(1).step_by(2) {
269 if token.contains(' ') || !token.contains('/') || token.contains("::") || token.starts_with("../") {
270 continue;
271 }
272 let path = token.trim_end_matches("/*").trim_end_matches('/');
273 let first = path.split('/').next().unwrap_or("");
274 let in_src = first == "src" || src_dirs.contains(first);
275 let looks_like_source = path.ends_with(".rs") || path.ends_with(".wgsl") || !path.contains('.');
276 if !in_src || !looks_like_source {
277 continue;
278 }
279 checked += 1;
280 if !(root.join(path).exists() || root.join("src").join(path).exists()) {
281 bad.push(format!("`{token}` is not a path in this crate"));
282 }
283 }
284 assert!(checked > 0, "no source path found in CLAUDE.md — did the spelling change?");
285 assert!(bad.is_empty(), "CLAUDE.md names source paths that do not exist:\n {}", bad.join("\n "));
286 }
287 }