use text_document::{Alignment, BlockFormat, MoveMode, TextDocument, TextFormat};
fn new_doc_with_text(text: &str) -> TextDocument {
let doc = TextDocument::new();
doc.set_plain_text(text).unwrap();
doc
}
#[test]
fn char_format_at_position() {
let doc = new_doc_with_text("Hello");
let cursor = doc.cursor();
let fmt = cursor.char_format().unwrap();
assert_eq!(fmt.font_bold, None);
assert_eq!(fmt.font_italic, None);
}
#[test]
fn set_char_format_bold() {
let doc = new_doc_with_text("Hello");
let cursor = doc.cursor();
cursor.set_position(0, MoveMode::MoveAnchor);
cursor.set_position(5, MoveMode::KeepAnchor);
let fmt = TextFormat {
font_bold: Some(true),
..Default::default()
};
cursor.set_char_format(&fmt).unwrap();
let read_cursor = doc.cursor_at(0);
let result_fmt = read_cursor.char_format().unwrap();
assert_eq!(result_fmt.font_bold, Some(true));
}
#[test]
fn merge_char_format_preserves_existing() {
let doc = new_doc_with_text("Hello");
let cursor = doc.cursor();
cursor.set_position(0, MoveMode::MoveAnchor);
cursor.set_position(5, MoveMode::KeepAnchor);
let bold_fmt = TextFormat {
font_bold: Some(true),
..Default::default()
};
cursor.set_char_format(&bold_fmt).unwrap();
let italic_fmt = TextFormat {
font_italic: Some(true),
..Default::default()
};
cursor.merge_char_format(&italic_fmt).unwrap();
let read_cursor = doc.cursor_at(0);
let result_fmt = read_cursor.char_format().unwrap();
assert_eq!(result_fmt.font_bold, Some(true));
assert_eq!(result_fmt.font_italic, Some(true));
}
#[test]
fn block_format_at_position() {
let doc = new_doc_with_text("Hello");
let cursor = doc.cursor();
let fmt = cursor.block_format().unwrap();
assert_eq!(fmt.alignment, None);
}
#[test]
fn set_block_format_alignment() {
let doc = new_doc_with_text("Hello");
let cursor = doc.cursor();
cursor.set_position(0, MoveMode::MoveAnchor);
cursor.set_position(5, MoveMode::KeepAnchor);
let fmt = BlockFormat {
alignment: Some(Alignment::Center),
..Default::default()
};
cursor.set_block_format(&fmt).unwrap();
let read_cursor = doc.cursor_at(0);
let result_fmt = read_cursor.block_format().unwrap();
assert_eq!(result_fmt.alignment, Some(Alignment::Center));
}
#[test]
fn set_char_format_is_undoable() {
let doc = new_doc_with_text("Hello");
let cursor = doc.cursor();
cursor.set_position(0, MoveMode::MoveAnchor);
cursor.set_position(5, MoveMode::KeepAnchor);
let fmt = TextFormat {
font_bold: Some(true),
..Default::default()
};
cursor.set_char_format(&fmt).unwrap();
assert!(doc.can_undo());
doc.undo().unwrap();
let read_cursor = doc.cursor_at(0);
let result_fmt = read_cursor.char_format().unwrap();
assert_ne!(result_fmt.font_bold, Some(true));
}
fn headings(doc: &TextDocument) -> Vec<u8> {
doc.blocks()
.iter()
.map(|b| b.block_format().heading_level.unwrap_or(0))
.collect()
}
fn two_paragraphs() -> (TextDocument, usize) {
let doc = new_doc_with_text("First para.\nSecond para.");
(doc, "First para.".chars().count())
}
#[test]
fn reading_a_block_format_at_a_paragraph_end_reads_that_paragraph() {
let (doc, end) = two_paragraphs();
let c = doc.cursor_at(0);
c.set_position(0, MoveMode::MoveAnchor);
c.set_block_format(&BlockFormat {
alignment: Some(Alignment::Center),
..Default::default()
})
.unwrap();
assert_eq!(
doc.block_format_at(end).unwrap().alignment,
Some(Alignment::Center),
"the caret has not left the first paragraph, so its format is the answer"
);
let caret = doc.cursor_at(end);
caret.set_position(end, MoveMode::MoveAnchor);
assert_eq!(
caret.block_format().unwrap().alignment,
Some(Alignment::Center)
);
assert_eq!(doc.block_format_at(end + 1).unwrap().alignment, None);
}
#[test]
fn applying_a_block_format_at_a_paragraph_end_formats_that_paragraph() {
let (doc, end) = two_paragraphs();
let caret = doc.cursor_at(end);
caret.set_position(end, MoveMode::MoveAnchor);
caret
.set_block_format(&BlockFormat {
heading_level: Some(1),
..Default::default()
})
.unwrap();
assert_eq!(
headings(&doc),
vec![1, 0],
"the heading belongs to the paragraph the caret was in — and must not \
be dropped on the floor"
);
}
#[test]
fn applying_a_block_format_at_a_paragraph_start_formats_that_paragraph() {
let (doc, end) = two_paragraphs();
let caret = doc.cursor_at(end + 1);
caret.set_position(end + 1, MoveMode::MoveAnchor);
caret
.set_block_format(&BlockFormat {
heading_level: Some(1),
..Default::default()
})
.unwrap();
assert_eq!(headings(&doc), vec![0, 1], "the crossing still happens");
}
#[test]
fn a_collapsed_caret_formats_exactly_one_block_at_every_position() {
for pos in 0..=new_doc_with_text("First para.\nSecond para.").character_count() {
let (doc, _) = two_paragraphs();
let caret = doc.cursor_at(pos);
caret.set_position(pos, MoveMode::MoveAnchor);
caret
.set_block_format(&BlockFormat {
heading_level: Some(1),
..Default::default()
})
.unwrap();
assert_eq!(
headings(&doc).iter().filter(|h| **h == 1).count(),
1,
"exactly one block must take the format (caret at {pos})"
);
}
}
#[test]
fn a_caret_in_an_empty_paragraph_formats_that_empty_paragraph() {
let doc = new_doc_with_text("Text.\n\nMore.");
let blank = "Text.\n".chars().count();
let caret = doc.cursor_at(blank);
caret.set_position(blank, MoveMode::MoveAnchor);
caret
.set_block_format(&BlockFormat {
heading_level: Some(2),
..Default::default()
})
.unwrap();
assert_eq!(headings(&doc), vec![0, 2, 0]);
}