use crate::compat::{String, ToString, Vec};
pub const HEADERS: [&str; 4] = ["Name", "Qty", "Price", "Status"];
pub const ROWS: [[&str; 4]; 6] = [
["Widget", "12", "12.50", "OK"],
["Gadget", "3", "240.00", "Low"],
["Doohickey", "48", "1.25", "OK"],
["Sprocket", "7", "88.75", "Hold"],
["Flange", "31", "9.99", "OK"],
["Cog", "1", "1200.00", "Low"],
];
pub const LIST_ITEMS: [&str; 6] = ["Widget", "Gadget", "Doohickey", "Sprocket", "Flange", "Cog"];
pub const MENU_ITEMS: [&str; 5] = ["New", "Open", "Save", "Export", "Close"];
pub const TAB_TITLES: [&str; 3] = ["Overview", "Details", "History"];
pub const BARS: [(&str, f64); 5] =
[("Mon", 12.0), ("Tue", 48.0), ("Wed", 31.0), ("Thu", 7.0), ("Fri", 25.0)];
pub const SLICES: [(&str, f64); 4] =
[("Alpha", 40.0), ("Beta", 30.0), ("Gamma", 20.0), ("Delta", 10.0)];
pub const SERIES: [(&str, [(f64, f64); 6]); 2] = [
("Series A", [(0.0, 12.0), (1.0, 19.0), (2.0, 14.0), (3.0, 27.0), (4.0, 22.0), (5.0, 31.0)]),
("Series B", [(0.0, 8.0), (1.0, 11.0), (2.0, 18.0), (3.0, 15.0), (4.0, 29.0), (5.0, 24.0)]),
];
pub const CANDLES: [(f64, f64, f64, f64); 4] = [
(20.0, 26.0, 18.0, 24.0),
(24.0, 29.0, 22.0, 23.0),
(23.0, 34.0, 21.0, 31.0),
(31.0, 33.0, 15.0, 19.0),
];
pub fn rows() -> Vec<Vec<String>> {
ROWS.iter().map(|row| row.iter().map(|cell| cell.to_string()).collect()).collect()
}
pub fn headers() -> Vec<String> {
HEADERS.iter().map(|header| header.to_string()).collect()
}
pub fn list_items() -> Vec<String> {
LIST_ITEMS.iter().map(|item| item.to_string()).collect()
}
pub fn menu_items() -> Vec<String> {
MENU_ITEMS.iter().map(|item| item.to_string()).collect()
}
pub fn tab_titles() -> Vec<String> {
TAB_TITLES.iter().map(|title| title.to_string()).collect()
}
pub fn bars() -> Vec<(String, f64)> {
BARS.iter().map(|(label, value)| (label.to_string(), *value)).collect()
}
pub const FONT_NAMES: [&str; 5] = ["Arial", "Helvetica", "Courier New", "Times New Roman", "Georgia"];
pub fn x_labels() -> Vec<String> {
["0", "1", "2", "3", "4", "5"].iter().map(|label| label.to_string()).collect()
}
pub fn tree_rows() -> Vec<String> {
let mut rows = Vec::new();
for (index, name) in LIST_ITEMS.iter().enumerate() {
if index < 2 {
rows.push(name.to_string());
rows.push(format!(" {name} · child 1"));
rows.push(format!(" {name} · child 2"));
} else {
rows.push(format!(" {name}"));
}
}
rows
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_row_fills_every_column() {
for (index, row) in ROWS.iter().enumerate() {
assert_eq!(
row.len(),
HEADERS.len(),
"row {index} has {} cells for {} headers",
row.len(),
HEADERS.len()
);
}
}
#[test]
fn the_sample_values_are_not_all_the_same() {
let quantities: Vec<&str> = ROWS.iter().map(|row| row[1]).collect();
let distinct = {
let mut sorted = quantities.clone();
sorted.sort_unstable();
sorted.dedup();
sorted.len()
};
assert!(distinct >= 4, "the quantity column has only {distinct} distinct values");
let statuses: Vec<&str> = ROWS.iter().map(|row| row[3]).collect();
let distinct_statuses = {
let mut sorted = statuses.clone();
sorted.sort_unstable();
sorted.dedup();
sorted.len()
};
assert!(distinct_statuses >= 2, "the status column is one repeated value");
}
#[test]
fn the_bar_and_series_values_span_a_range() {
let values: Vec<f64> = BARS.iter().map(|(_, value)| *value).collect();
let min = values.iter().cloned().fold(f64::INFINITY, f64::min);
let max = values.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
assert!(max >= min * 3.0, "the bars span only {min}..{max}, which renders as a flat row");
let (_, first) = SERIES[0];
let min_y = first.iter().map(|(_, y)| *y).fold(f64::INFINITY, f64::min);
let max_y = first.iter().map(|(_, y)| *y).fold(f64::NEG_INFINITY, f64::max);
assert!(max_y - min_y > 10.0, "the first series is nearly flat: {min_y}..{max_y}");
}
#[test]
fn every_candle_has_a_body_inside_its_range() {
for (index, (open, high, low, close)) in CANDLES.iter().enumerate() {
let (open, high, low, close) = (*open, *high, *low, *close);
assert!(
high >= open.max(close),
"candle {index}: high {high} is below the body ({open}, {close})"
);
assert!(
low <= open.min(close),
"candle {index}: low {low} is above the body ({open}, {close})"
);
}
}
#[test]
fn the_owned_accessors_mirror_the_constants() {
assert_eq!(headers().len(), HEADERS.len());
assert_eq!(rows().len(), ROWS.len());
assert_eq!(rows()[0].len(), HEADERS.len());
assert_eq!(list_items().len(), LIST_ITEMS.len());
assert_eq!(menu_items().len(), MENU_ITEMS.len());
assert_eq!(tab_titles().len(), TAB_TITLES.len());
assert_eq!(bars().len(), BARS.len());
assert_eq!(bars()[0].0, BARS[0].0);
assert_eq!(x_labels().len(), SERIES[0].1.len());
}
}