datui_lib/widgets/ui/
mod.rs1mod form_row;
10mod hintbar;
11mod picker;
12mod section_rule;
13mod surface;
14mod working;
15
16pub use form_row::{FormRow, FormValue};
17pub use hintbar::HintBar;
18pub use picker::{Clicks, Picker, PickerState};
19pub use section_rule::SectionRule;
20pub use surface::Surface;
21pub use working::Working;
22
23#[cfg(test)]
24mod tests {
25 use std::path::{Path, PathBuf};
26
27 const ALLOWED: &[&str] = &[];
31
32 const FRAMES: &[&str] = &[
35 "Borders::",
36 "Block::bordered",
37 ".border_set(",
38 ".border_type(",
39 ];
40
41 fn rust_files(dir: &Path, out: &mut Vec<PathBuf>) {
42 for entry in std::fs::read_dir(dir).expect("source dir") {
43 let path = entry.expect("dir entry").path();
44 if path.is_dir() {
45 rust_files(&path, out);
46 } else if path.extension().is_some_and(|ext| ext == "rs") {
47 out.push(path);
48 }
49 }
50 }
51
52 fn frames_in(source: &str) -> Vec<(usize, &str)> {
54 source
55 .lines()
56 .enumerate()
57 .filter(|(_, line)| {
58 let code = line.trim_start().replace("Borders::NONE", "");
59 !code.starts_with("//") && FRAMES.iter().any(|frame| code.contains(frame))
60 })
61 .map(|(i, line)| (i + 1, line.trim()))
62 .collect()
63 }
64
65 #[test]
69 fn only_the_surface_draws_a_frame() {
70 let src = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
71 let kit = src.join("widgets").join("ui");
72 let mut files = Vec::new();
73 rust_files(&src, &mut files);
74 for dir in ["render", "widgets"] {
75 assert!(
76 files.iter().any(|path| path.starts_with(src.join(dir))),
77 "the scan reads src/{dir}"
78 );
79 }
80 let mut found = Vec::new();
81 for path in files.iter().filter(|path| !path.starts_with(&kit)) {
82 let name = path
83 .strip_prefix(&src)
84 .expect("under src")
85 .to_string_lossy()
86 .replace('\\', "/");
87 let source = std::fs::read_to_string(path).expect("source file");
88 let frames = frames_in(&source);
89 if ALLOWED.contains(&name.as_str()) {
90 assert!(
91 !frames.is_empty(),
92 "{name} is allowed a frame it no longer draws"
93 );
94 continue;
95 }
96 found.extend(
97 frames
98 .into_iter()
99 .map(|(line, code)| format!(" {name}:{line}: {code}")),
100 );
101 }
102 assert!(
103 found.is_empty(),
104 "draw these frames with widgets::ui::Surface:\n{}",
105 found.join("\n")
106 );
107 }
108
109 #[test]
111 fn the_frame_scan_reads_code_only() {
112 let source = [
113 "let a = Block::default().borders(Borders::ALL);",
114 "let b = Block::bordered();",
115 "let c = Block::default().borders(Borders::NONE);",
116 "// Borders::ALL was here once.",
117 "let d = Block::default().borders(Borders::TOP | Borders::BOTTOM);",
118 ]
119 .join("\n");
120 let lines: Vec<usize> = frames_in(&source).into_iter().map(|(n, _)| n).collect();
121 assert_eq!(lines, [1, 2, 5]);
122 }
123}