use serde::Serialize;
use shep_core::protocol::Lamb;
use crate::output::Render;
use crate::style::Presentation;
use crate::terminal_safe::sanitise;
use super::toolkit::{Paint, paint};
#[derive(Debug, Serialize)]
pub struct LambRows(pub Vec<Lamb>);
impl Render for LambRows {
fn headers() -> &'static [&'static str] {
&["PID", "NAME"]
}
fn rows(&self) -> Vec<Vec<String>> {
self.0
.iter()
.map(|lamb| vec![lamb.pid.to_string(), lamb.name.clone()])
.collect()
}
#[track_caller]
fn json_key_for(header: &str) -> &'static str {
match header {
"PID" => "pid",
"NAME" => "name",
other => panic!("LambRows::headers() does not include {other:?}"),
}
}
const JSON_ONLY: &'static [&'static str] = &[];
const PRIORITIES: &'static [u8] = &[0, 0];
}
#[derive(Debug, Serialize)]
pub struct LabelledLambRows(pub Vec<Lamb>);
impl LabelledLambRows {
pub fn wanted_for(lambs: &[Lamb]) -> bool {
lambs.iter().any(|lamb| lamb.label.is_some())
}
}
impl Render for LabelledLambRows {
fn headers() -> &'static [&'static str] {
&["PID", "NAME", "LABEL"]
}
fn rows(&self) -> Vec<Vec<String>> {
self.0
.iter()
.map(|lamb| {
vec![
lamb.pid.to_string(),
lamb.name.clone(),
lamb.label
.as_deref()
.map_or_else(|| "-".to_string(), |label| sanitise(label).0),
]
})
.collect()
}
fn rows_for(&self, presentation: Presentation, status_word: bool) -> Vec<Vec<String>> {
paint(
self.rows(),
Self::headers(),
presentation,
status_word,
|_, _, _| Paint::Default,
)
}
#[track_caller]
fn json_key_for(header: &str) -> &'static str {
match header {
"PID" => "pid",
"NAME" => "name",
"LABEL" => "label",
other => panic!("LabelledLambRows::headers() does not include {other:?}"),
}
}
const JSON_ONLY: &'static [&'static str] = &[];
const PRIORITIES: &'static [u8] = &[0, 0, 6];
}
#[cfg(test)]
mod tests {
use crate::vocabulary::Role;
use super::super::tests::{assert_no_drift, coloured, painted};
use super::*;
#[test]
fn lamb_rows_do_not_drift() {
assert_no_drift(
&LambRows(vec![Lamb::new(4243, "node"), Lamb::new(4244, "sh")]),
|j| &j[0],
&[],
);
}
#[test]
fn lamb_rows_carry_no_colour_at_all() {
let rows = LambRows(vec![Lamb::new(48_302, "node")]).rows_for(coloured(), true);
assert_eq!(rows[0], vec!["48302".to_string(), "node".to_string()]);
}
#[test]
fn labelled_lamb_rows_do_not_drift() {
assert_no_drift(
&LabelledLambRows(vec![
Lamb::new(4243, "python").with_label("worker 1"),
Lamb::new(4244, "sh"),
]),
|j| &j[0],
&[],
);
}
#[test]
fn only_a_missing_label_is_painted() {
let rows = LabelledLambRows(vec![
Lamb::new(48_302, "python").with_label("worker 1"),
Lamb::new(48_303, "sh"),
])
.rows_for(coloured(), true);
assert_eq!(
rows,
vec![
vec![
"48302".to_string(),
"python".to_string(),
"worker 1".to_string()
],
vec![
"48303".to_string(),
"sh".to_string(),
painted("-", Role::Ink3)
],
]
);
}
#[test]
fn a_label_is_sanitised_before_it_reaches_the_cell() {
let rows = LabelledLambRows(vec![
Lamb::new(48_302, "python").with_label("worker\u{202e}1"),
])
.rows();
assert_eq!(rows[0][2], "worker1");
}
#[test]
fn the_labelled_table_is_wanted_only_once_a_lamb_has_a_label() {
assert!(!LabelledLambRows::wanted_for(&[]));
assert!(!LabelledLambRows::wanted_for(&[Lamb::new(1, "sh")]));
assert!(LabelledLambRows::wanted_for(&[
Lamb::new(1, "sh"),
Lamb::new(2, "sh").with_label("b"),
]));
}
}