//! Pasting a URL over selected text makes a markdown link; every other paste //! stays a plain paste. use notescraft_editor::keys::{self, Edit}; fn applied(text: &str, edit: &Edit) -> String { let mut out = String::from(text); out.replace_range(edit.range.clone(), &edit.insert); out } fn link(text: &str, range: std::ops::Range, pasted: &str) -> Option { keys::on_paste_url(text, range, pasted).map(|edit| applied(text, &edit)) } const URL: &str = "https://example.com"; #[test] fn a_plain_word_becomes_a_link() { let text = "hello world"; assert_eq!(link(text, 6..11, URL), Some(String::from("hello [world](https://example.com)"))); } #[test] fn a_phrase_becomes_a_link() { let text = "the quick brown fox"; assert_eq!(link(text, 4..15, URL), Some(String::from("the [quick brown](https://example.com) fox"))); } #[test] fn the_cursor_ends_after_the_closing_paren() { let text = "hello world"; let edit = keys::on_paste_url(text, 6..11, URL).unwrap(); assert_eq!(edit.sel, 34..34); assert_eq!(edit.range, 6..11); } #[test] fn brackets_in_the_selection_are_escaped() { let text = "a [b] c"; assert_eq!(link(text, 0..7, URL), Some(String::from("[a \\[b\\] c](https://example.com)"))); } #[test] fn a_wrapped_selection_keeps_its_label() { let text = "[label](old)"; assert_eq!(link(text, 0..12, URL), Some(String::from("[label](https://example.com)"))); let text = "[label]"; assert_eq!(link(text, 0..7, URL), Some(String::from("[label](https://example.com)"))); } #[test] fn an_angle_bracketed_url_is_unwrapped() { let text = "hello world"; assert_eq!(link(text, 6..11, ""), Some(String::from("hello [world](https://example.com)"))); } #[test] fn other_schemes_are_refused() { let text = "hello"; assert!(link(text, 0..5, "javascript:alert(1)").is_none()); assert!(link(text, 0..5, "file:///etc/passwd").is_none()); assert!(link(text, 0..5, "mailto:me@example.com").is_none()); } #[test] fn a_url_with_spaces_is_refused() { let text = "hello"; assert!(link(text, 0..5, "https://example.com/a b").is_none()); } #[test] fn a_host_without_a_dot_is_refused() { let text = "hello"; assert!(link(text, 0..5, "http://example").is_none()); assert!(link(text, 0..5, "http://localhost:8080/x").is_some()); } #[test] fn the_scheme_is_case_insensitive() { let text = "hello"; assert!(link(text, 0..5, "HTTPS://EXAMPLE.COM").is_some()); } #[test] fn a_url_over_2048_bytes_is_refused() { let text = "hello"; let fits = format!("https://example.com/{}", "x".repeat(2028)); assert_eq!(fits.len(), 2048); assert!(link(text, 0..5, &fits).is_some()); let too_long = format!("https://example.com/{}", "x".repeat(2029)); assert!(link(text, 0..5, &too_long).is_none()); } #[test] fn an_empty_selection_is_refused() { let text = "hello world"; assert!(link(text, 6..6, URL).is_none()); } #[test] fn a_selection_inside_a_fenced_block_is_refused() { let text = "```rust\nfn main() {}\n```"; let start = text.find("fn main").unwrap(); assert!(link(text, start..start + 9, URL).is_none()); } #[test] fn a_selection_inside_inline_code_is_refused() { let text = "a `code` b"; let start = text.find("code").unwrap(); assert!(link(text, start..start + 4, URL).is_none()); } #[test] fn a_selection_inside_a_link_is_refused() { let text = "[label](https://example.com)"; let start = text.find("label").unwrap(); assert!(link(text, start..start + 5, URL).is_none()); } #[test] fn a_multi_line_selection_is_refused() { let text = "one\ntwo"; assert!(link(text, 0..7, URL).is_none()); } #[test] fn a_selection_over_500_bytes_is_refused() { let text = "x".repeat(501); assert!(link(&text, 0..501, URL).is_none()); let text = "x".repeat(500); assert!(link(&text, 0..500, URL).is_some()); } #[test] fn a_selection_that_is_a_url_pastes_normally() { let text = "https://example.com"; assert!(link(text, 0..19, URL).is_none()); } #[test] fn unicode_offsets_are_kept() { let text = "caf\u{e9} na\u{ef}ve"; let start = text.find("na\u{ef}ve").unwrap(); let (head, tail) = text.split_at_checked(start).unwrap(); assert_eq!(head, "caf\u{e9} "); assert_eq!(tail, "na\u{ef}ve"); assert_eq!(link(text, start..start + tail.len(), URL), Some(String::from("caf\u{e9} [na\u{ef}ve](https://example.com)"))); } #[test] fn a_second_paste_changes_nothing() { let text = "hello world"; let edit = keys::on_paste_url(text, 6..11, URL).unwrap(); let linked = applied(text, &edit); assert_eq!(keys::on_paste_url(text, 6..11, URL), Some(edit.clone())); assert!(keys::on_paste_url(&linked, edit.sel.clone(), URL).is_none()); }