//! Inline mark toggles. use notescraft_editor::marks::{Mark, active_marks, toggle_mark}; #[test] fn wrap_and_unwrap_each_mark() { for (mark, wrapped) in [(Mark::Bold, "a **b** c"), (Mark::Italic, "a *b* c"), (Mark::Strike, "a ~~b~~ c"), (Mark::Code, "a `b` c"), (Mark::Highlight, "a ==b== c")] { let on = toggle_mark("a b c", 2..3, mark).unwrap(); assert_eq!(on.text, wrapped); assert_eq!(&on.text[on.sel.clone()], "b"); assert!(active_marks(&on.text, on.sel.clone()).contains(&mark)); let off = toggle_mark(&on.text, on.sel.clone(), mark).unwrap(); assert_eq!(off.text, "a b c", "{mark:?}"); assert_eq!(&off.text[off.sel.clone()], "b"); let mut applied = "a b c".to_owned(); applied.replace_range(on.replace.0.clone(), &on.replace.1); assert_eq!(applied, on.text); } } #[test] fn unwrap_when_selection_includes_markers() { let off = toggle_mark("a **b** c", 2..7, Mark::Bold).unwrap(); assert_eq!(off.text, "a b c"); assert_eq!(active_marks("a **b** c", 2..7), vec![Mark::Bold]); } #[test] fn bold_and_italic_nest() { let b = toggle_mark("x", 0..1, Mark::Bold).unwrap(); assert_eq!(active_marks(&b.text, b.sel.clone()), vec![Mark::Bold]); let bi = toggle_mark(&b.text, b.sel.clone(), Mark::Italic).unwrap(); assert_eq!(bi.text, "***x***"); assert_eq!(active_marks(&bi.text, bi.sel.clone()), vec![Mark::Bold, Mark::Italic]); let only_b = toggle_mark(&bi.text, bi.sel.clone(), Mark::Italic).unwrap(); assert_eq!(only_b.text, "**x**"); let only_i = toggle_mark(&bi.text, bi.sel.clone(), Mark::Bold).unwrap(); assert_eq!(only_i.text, "*x*"); } #[test] fn link_wraps_with_caret_in_url_and_toggles_back() { let on = toggle_mark("see site now", 4..8, Mark::Link).unwrap(); assert_eq!(on.text, "see [site]() now"); assert_eq!(on.sel, 11..11); assert!(active_marks(&on.text, on.sel.clone()).contains(&Mark::Link)); let off = toggle_mark(&on.text, on.sel.clone(), Mark::Link).unwrap(); assert_eq!(off.text, "see site now"); let off2 = toggle_mark("see [site](http://x) now", 4..20, Mark::Link).unwrap(); assert_eq!(off2.text, "see site now"); let off3 = toggle_mark("see [site](http://x) now", 5..9, Mark::Link).unwrap(); assert_eq!(off3.text, "see site now"); } #[test] fn empty_selection_inserts_pair_and_toggles_back() { let on = toggle_mark("ab", 1..1, Mark::Bold).unwrap(); assert_eq!(on.text, "a****b"); assert_eq!(on.sel, 3..3); assert_eq!(toggle_mark(&on.text, on.sel, Mark::Bold).unwrap().text, "ab"); } #[test] fn multibyte_and_hostile() { let t = "é日本語 ok"; let on = toggle_mark(t, 0..2, Mark::Strike).unwrap(); assert_eq!(on.text, "~~é~~日本語 ok"); assert!(toggle_mark(t, 1..2, Mark::Bold).is_err()); assert!(toggle_mark(t, 0..99, Mark::Bold).is_err()); assert!(toggle_mark(t, std::ops::Range { start: 3, end: 1 }, Mark::Bold).is_err()); assert_eq!(active_marks(t, 1..2), vec![]); for text in ["", "*", "**", "***", "[", "](", "[]()", "`", "====", "~~"] { for s in 0..=text.len() { for e in s..=text.len() { for m in Mark::ALL { let _ = active_marks(text, s..e); let _ = toggle_mark(text, s..e, m); } } } } let big = "word ".repeat(100_000); let on = toggle_mark(&big, 5..9, Mark::Italic).unwrap(); assert_eq!(toggle_mark(&on.text, on.sel, Mark::Italic).unwrap().text, big); }