use crate::{Device, Scan, Style, demo, device_table, footer, services_table, tui};
use std::net::Ipv4Addr;
use std::path::Path;
fn scanned() -> Scan {
let mut scan = demo::scan();
scan.summary = scan.summary.replace("(demo)", "(en0) in 2.0s");
demo::memory().mark(&mut scan);
scan
}
fn below(scan: &Scan) -> String {
let mut out = String::from("\n");
for line in footer(scan) {
out.push_str(&line);
out.push('\n');
}
out
}
fn present(scan: &Scan) -> Vec<Device> {
scan.present().cloned().collect()
}
fn plain(table: String) -> String {
table
.lines()
.map(|l| l.trim_end().to_string() + "\n")
.collect()
}
fn browser(show_services: bool, ip: &str, port: Option<u16>) -> String {
let scan = scanned();
let rows = if show_services {
crate::services::list(&scan.devices).len()
} else {
scan.devices.len()
};
let height = 1 + scan.changes.iter().count() + scan.notes.len() + 3 + rows + 1;
let ip: Ipv4Addr = ip.parse().unwrap();
tui::screen(scan, show_services, (ip, port), 124, height as u16)
}
fn examples() -> Vec<(&'static str, String)> {
let scan = scanned();
let devices = present(&scan);
let some: Vec<_> = present(&scan)
.into_iter()
.filter(|d| {
[
"192.168.1.52",
"192.168.1.112",
"192.168.1.130",
"192.168.1.230",
]
.contains(&d.ip.to_string().as_str())
})
.collect();
vec![
("$ lsnet", browser(false, "192.168.1.52", None)),
("$ lsnet -s", browser(true, "192.168.1.14", Some(32400))),
(
"$ lsnet -l",
plain(device_table(&devices, false, Style::Plain)) + &below(&scan),
),
(
"$ lsnet -s -l",
plain(services_table(&devices, Style::Plain)) + &below(&scan),
),
(
"$ sudo lsnet -l",
plain(device_table(&some, false, Style::Plain)),
),
]
}
fn block(readme: &str, command: &str) -> Option<std::ops::Range<usize>> {
let opening = format!("```\n{command}\n");
let start = readme.find(&opening)? + opening.len();
let end = start + readme[start..].find("```\n")?;
Some(start..end)
}
#[test]
fn readme_shows_the_demo_network() {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("README.md");
let mut readme = std::fs::read_to_string(&path).unwrap();
let update = std::env::var_os("LSNET_UPDATE_README").is_some();
let mut stale = Vec::new();
for (command, want) in examples() {
let range = block(&readme, command)
.unwrap_or_else(|| panic!("README.md has no example starting `{command}`"));
if readme[range.clone()] != want {
stale.push(command);
readme.replace_range(range, &want);
}
}
if update {
std::fs::write(&path, readme).unwrap();
} else {
assert!(
stale.is_empty(),
"README.md's examples for {stale:?} don't match the demo network; \
LSNET_UPDATE_README=1 cargo test readme rewrites them"
);
}
}