use serde_json::json;
use super::tests::{Place, harness, read_card, say};
use super::*;
use crate::provider::fake::{FakeServer, calls, says};
const SIZES: [(u16, u16); 4] = [(10, 3), (40, 10), (80, 24), (200, 60)];
fn top(screen: &str) -> &str {
screen.lines().next().unwrap_or_default()
}
fn no_half_names(screen: &str, names: &[&str]) {
let bar = top(screen);
for name in names {
if bar.contains(name) {
continue;
}
let cut = (3..name.chars().count()).map(|n| name.chars().take(n).collect::<String>()).rev();
for start in cut {
assert!(!bar.contains(&format!("{start}…")), "`{name}` is cut on the top bar: {bar:?}");
}
}
}
fn with_a_card(place: &Place, width: u16, height: u16, command: &str) -> Harness<QCli> {
let server =
FakeServer::start(vec![(200, calls("r1", "run_command", &json!({"command": command}))), (200, says("ok"))]);
let mut harness = harness(place.app(Some(&server.address)));
say(&mut harness, "run it");
read_card(&mut harness);
harness.resize(width, height);
std::mem::forget(server);
harness
}
#[test]
fn every_state_is_drawn_at_every_size_without_a_panic() {
for (width, height) in SIZES {
let place = Place::new(&format!("sizes-empty-{width}x{height}"));
let mut empty = harness(place.app(None));
empty.resize(width, height);
let _ = empty.screen();
let long = format!("printf '{}'", "x".repeat(400));
let _ = with_a_card(&place, width, height, &long).screen();
let refused = FakeServer::start(vec![(401, json!({"error": {"message": "no"}}).to_string())]);
let mut notice = harness(place.app(Some(&refused.address)));
say(&mut notice, "hi");
notice.resize(width, height);
let _ = notice.screen();
}
}
#[test]
fn a_card_keeps_both_its_buttons_in_view_wherever_they_fit() {
for (width, height) in SIZES.into_iter().filter(|(width, height)| *width >= 40 && *height >= 10) {
let place = Place::new(&format!("sizes-card-{width}x{height}"));
let long: String = (1..=40).map(|n| format!("echo line {n}\n")).collect();
let harness = with_a_card(&place, width, height, &long);
let screen = harness.screen();
assert!(screen.contains("Allow"), "{width}×{height}: Allow is in view:\n{screen}");
assert!(screen.contains("Decline"), "{width}×{height}: Decline is in view:\n{screen}");
}
}
#[test]
fn the_top_bar_never_shows_half_a_name() {
for (width, height) in SIZES {
let place = Place::new(&format!("sizes-bar-{width}x{height}"));
let mut harness = harness(place.app(None));
harness.resize(width, height);
let screen = harness.screen();
no_half_names(&screen, &["qcli", "work"]);
}
}
#[test]
fn a_narrow_top_bar_gives_up_the_model_first_and_shortens_the_folder_in_its_middle() {
let long = "a-project-folder-with-a-very-long-name";
let bar = |width: u16| {
let place = Place::new(&format!("sizes-long-folder-{width}"));
let folder = place.work().join(long);
std::fs::create_dir_all(&folder).expect("the folder");
let app = QCli::new(
Workspace::new(&folder).expect("the workspace"),
place.store(),
place.settings(Some("http://127.0.0.1:1")),
);
let mut harness = harness(app);
harness.resize(width, 24);
top(&harness.screen()).trim().to_owned()
};
assert_eq!(bar(80), format!("qcli {long} test-model"), "all of it fits");
let forty = bar(40);
assert!(!forty.contains("test"), "the model goes first, whole: {forty:?}");
assert!(forty.starts_with("qcli a-project"), "qcli's name and the folder's start stay: {forty:?}");
assert!(forty.ends_with("long-name"), "and the folder's end: {forty:?}");
assert!(forty.contains('…'), "the middle is left out: {forty:?}");
let fifteen = bar(15);
assert!(!fifteen.contains("qc"), "qcli's name goes before it would be cut: {fifteen:?}");
assert!(fifteen.ends_with("name"), "the folder keeps its end: {fifteen:?}");
no_half_names(&bar(10), &["qcli", "test-model"]);
}
#[test]
fn the_provider_form_can_be_saved_at_a_small_size() {
for (width, height) in [(40, 10), (80, 24)] {
let place = Place::new(&format!("sizes-form-{width}x{height}"));
let mut harness = harness(place.app(None));
harness.resize(width, height);
let screen = harness.screen();
assert!(screen.contains("Save"), "{width}×{height}: Save is in view:\n{screen}");
assert!(screen.contains("Cancel"), "{width}×{height}: Cancel is in view:\n{screen}");
}
}