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