138 lines
6.1 KiB
Rust
138 lines
6.1 KiB
Rust
//! Icon, colour and banner properties of a note.
|
|
|
|
use notescraft_index::{BannerTarget, ColorRef, DecorKeys, IconRef, Index, decor_from_props, parse_color, parse_icon};
|
|
use notescraft_markdown::Value;
|
|
|
|
fn props(pairs: &[(&str, Value)]) -> Vec<(String, Value)> {
|
|
pairs.iter().map(|(key, value)| ((*key).to_string(), value.clone())).collect()
|
|
}
|
|
|
|
fn text(value: &str) -> Value {
|
|
Value::String(value.to_string())
|
|
}
|
|
|
|
#[test]
|
|
fn the_lucide_spellings_name_the_same_icon() {
|
|
for raw in ["LiRocket", "lucide-rocket", "Rocket", "rocket"] {
|
|
assert_eq!(parse_icon(raw), Some(IconRef::Lucide("rocket".to_string())), "{raw}");
|
|
}
|
|
assert_eq!(parse_icon("LiArrowRight"), Some(IconRef::Lucide("arrow-right".to_string())));
|
|
assert_eq!(parse_icon("List"), Some(IconRef::Lucide("list".to_string())));
|
|
assert_eq!(parse_icon("rocket-launch"), Some(IconRef::Lucide("rocket-launch".to_string())));
|
|
}
|
|
|
|
#[test]
|
|
fn a_value_that_names_no_icon_is_ignored() {
|
|
assert_eq!(parse_icon(""), None);
|
|
assert_eq!(parse_icon(" "), None);
|
|
assert_eq!(parse_icon("rocket launch"), None);
|
|
assert_eq!(parse_icon("#ff8800"), None);
|
|
assert_eq!(parse_icon(&"a".repeat(65)), None);
|
|
assert!(parse_icon(&"a".repeat(64)).is_some());
|
|
}
|
|
|
|
#[test]
|
|
fn one_emoji_is_an_icon() {
|
|
assert_eq!(parse_icon("🚀"), Some(IconRef::Emoji("🚀".to_string())));
|
|
assert_eq!(parse_icon("👩💻"), Some(IconRef::Emoji("👩💻".to_string())));
|
|
assert_eq!(parse_icon("❤️"), Some(IconRef::Emoji("❤️".to_string())));
|
|
assert_eq!(parse_icon("👩💻🚀"), None);
|
|
assert_eq!(parse_icon("🚀 rocket"), None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_link_names_a_file_of_the_vault() {
|
|
assert_eq!(parse_icon("[[icons/star.svg]]"), Some(IconRef::File("icons/star.svg".to_string())));
|
|
assert_eq!(parse_icon("![[x.jpg]]"), Some(IconRef::File("x.jpg".to_string())));
|
|
assert_eq!(parse_icon("[[x.jpg|alias]]"), Some(IconRef::File("x.jpg".to_string())));
|
|
assert_eq!(parse_icon("icons/star.svg"), Some(IconRef::File("icons/star.svg".to_string())));
|
|
assert_eq!(parse_icon("[[]]"), None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_colour_is_hex_or_a_token() {
|
|
assert_eq!(parse_color("#f80"), Some(ColorRef::Rgb(255, 136, 0)));
|
|
assert_eq!(parse_color("#FF8800"), Some(ColorRef::Rgb(255, 136, 0)));
|
|
assert_eq!(parse_color("accent"), Some(ColorRef::Token("accent".to_string())));
|
|
assert_eq!(parse_color("danger"), Some(ColorRef::Token("danger".to_string())));
|
|
assert_eq!(parse_color("#12"), None);
|
|
assert_eq!(parse_color("#ff88"), None);
|
|
assert_eq!(parse_color("rgb(1,2,3)"), None);
|
|
assert_eq!(parse_color("Accent"), None);
|
|
assert_eq!(parse_color(""), None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_banner_is_a_file_or_a_url() {
|
|
let keys = DecorKeys::default();
|
|
let decor = decor_from_props(&props(&[("banner", text("[[cover.jpg]]"))]), &keys);
|
|
let banner = decor.banner.expect("banner");
|
|
assert_eq!(banner.target, BannerTarget::File("cover.jpg".to_string()));
|
|
assert!((banner.x - 0.5).abs() < f32::EPSILON);
|
|
assert!((banner.y - 0.5).abs() < f32::EPSILON);
|
|
|
|
let decor = decor_from_props(&props(&[("banner", text("https://example.com/a.png"))]), &keys);
|
|
assert_eq!(decor.banner.expect("banner").target, BannerTarget::Url("https://example.com/a.png".to_string()));
|
|
}
|
|
|
|
#[test]
|
|
fn the_focus_of_the_banner_is_a_number_in_range() {
|
|
let keys = DecorKeys::default();
|
|
let focus = |pairs: &[(&str, Value)]| decor_from_props(&props(pairs), &keys).banner.expect("banner").y;
|
|
let banner = [("banner", text("[[cover.jpg]]"))];
|
|
let with = |key: &str, value: Value| {
|
|
let mut pairs = banner.to_vec();
|
|
pairs.push((key, value));
|
|
focus(&pairs)
|
|
};
|
|
assert!((with("banner_y", Value::Number(0.2)) - 0.2).abs() < 1e-6);
|
|
assert!((with("banner_y", text("0.2")) - 0.2).abs() < 1e-6);
|
|
assert!((with("banner_y", Value::Number(-1.0)) - 0.5).abs() < f32::EPSILON);
|
|
assert!((with("banner_y", Value::Number(1.5)) - 0.5).abs() < f32::EPSILON);
|
|
assert!((with("banner_y", text("NaN")) - 0.5).abs() < f32::EPSILON);
|
|
assert!((with("banner_y", text("top")) - 0.5).abs() < f32::EPSILON);
|
|
assert!((with("banner_x", Value::Number(0.25)) - 0.5).abs() < f32::EPSILON);
|
|
}
|
|
|
|
#[test]
|
|
fn a_long_value_is_ignored() {
|
|
let keys = DecorKeys::default();
|
|
let long = "a".repeat(2048);
|
|
let decor = decor_from_props(&props(&[("icon", text(&long)), ("banner", text(&long))]), &keys);
|
|
assert_eq!(decor.icon, None);
|
|
assert_eq!(decor.banner, None);
|
|
}
|
|
|
|
#[test]
|
|
fn the_banner_emoji_is_the_icon_when_the_note_has_none() {
|
|
let keys = DecorKeys::default();
|
|
let decor = decor_from_props(&props(&[("banner_icon", text("🚀"))]), &keys);
|
|
assert_eq!(decor.icon, Some(IconRef::Emoji("🚀".to_string())));
|
|
let decor = decor_from_props(&props(&[("icon", text("LiRocket")), ("banner_icon", text("🚀"))]), &keys);
|
|
assert_eq!(decor.icon, Some(IconRef::Lucide("rocket".to_string())));
|
|
}
|
|
|
|
#[test]
|
|
fn the_keys_are_configurable() {
|
|
let keys = DecorKeys { icon: "cover", color: "coverColor", banner: "coverImage" };
|
|
let decor = decor_from_props(&props(&[("cover", text("star")), ("coverColor", text("#ff8800")), ("coverImage", text("[[a.png]]"))]), &keys);
|
|
assert_eq!(decor.icon, Some(IconRef::Lucide("star".to_string())));
|
|
assert_eq!(decor.color, Some(ColorRef::Rgb(255, 136, 0)));
|
|
assert_eq!(decor.banner.expect("banner").target, BannerTarget::File("a.png".to_string()));
|
|
let decor = decor_from_props(&props(&[("icon", text("star"))]), &keys);
|
|
assert_eq!(decor.icon, None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_note_is_decorated_from_its_frontmatter() {
|
|
let mut index = Index::new();
|
|
index.update_note("a.md", "---\nicon: LiRocket\niconColor: \"#ff8800\"\nbanner: \"[[cover.jpg]]\"\nbanner_y: 0.2\n---\nbody\n").unwrap();
|
|
let note_props = index.note_props("a.md").unwrap();
|
|
let decor = decor_from_props(note_props, &DecorKeys::default());
|
|
assert_eq!(decor.icon, Some(IconRef::Lucide("rocket".to_string())));
|
|
assert_eq!(decor.color, Some(ColorRef::Rgb(255, 136, 0)));
|
|
let banner = decor.banner.expect("banner");
|
|
assert_eq!(banner.target, BannerTarget::File("cover.jpg".to_string()));
|
|
assert!((banner.y - 0.2).abs() < 1e-6);
|
|
}
|