use std::sync::Arc;
use crate::color::Color;
use crate::text::Font;
use crate::widgets::rich_text::commands::RichCommand;
use crate::widgets::rich_text::model::{Block, DocPos, DocRange, InlineStyle, RichDoc};
use crate::widgets::rich_text::view::SharedResolver;
use crate::widgets::rich_text::RichTextEdit;
use super::core::RichEditCore;
const FONT_BYTES: &[u8] = include_bytes!("../../../../../demo/assets/Arial-Regular.ttf");
fn resolver() -> SharedResolver {
let font = Arc::new(Font::from_slice(FONT_BYTES).expect("test font loads"));
std::rc::Rc::new(move |_: &InlineStyle| Arc::clone(&font))
}
#[test]
fn handle_select_all_then_bold() {
let editor = RichTextEdit::new(RichDoc::from_blocks(vec![Block::plain("hello")]), resolver());
let handle = editor.handle();
handle.select_all();
assert_eq!(
handle.selection(),
DocRange::new(DocPos::new(0, 0), DocPos::new(0, 5)),
);
handle.exec(&RichCommand::ToggleBold);
assert_eq!(handle.common_style_of_selection().bold, Some(true));
assert_eq!(handle.plain_text(), "hello");
}
#[test]
fn handle_set_selection_clamps() {
let editor = RichTextEdit::new(RichDoc::from_blocks(vec![Block::plain("hi")]), resolver());
let handle = editor.handle();
handle.set_selection(DocRange::new(DocPos::new(9, 9), DocPos::new(0, 99)));
let sel = handle.selection();
assert_eq!(sel.start, DocPos::new(0, 2), "anchor clamped to end of block");
assert_eq!(sel.end, DocPos::new(0, 2), "caret clamped to end of block");
handle.set_caret(DocPos::new(0, 50));
assert!(handle.selection().is_empty());
assert_eq!(handle.selection().start, DocPos::new(0, 2));
}
#[test]
fn handle_load_replaces_content() {
let editor = RichTextEdit::new(RichDoc::from_blocks(vec![Block::plain("old")]), resolver());
let handle = editor.handle();
handle.select_all();
handle.load(RichDoc::from_blocks(vec![Block::plain("brand new")]));
assert_eq!(handle.plain_text(), "brand new");
assert_eq!(handle.selection().start, DocPos::new(0, 0));
assert!(handle.selection().is_empty(), "caret collapsed after load");
}
#[test]
fn load_resets_undo_history() {
let mut core = RichEditCore::new(RichDoc::from_blocks(vec![Block::plain("old")]), 16.0);
core.feed_undo(0.0);
core.select_all();
core.exec(&RichCommand::ToggleBold);
core.feed_undo(0.1);
core.feed_undo(2.0);
assert!(core.can_undo(), "edit created an undo point");
core.load(RichDoc::from_blocks(vec![Block::plain("brand new")]));
assert_eq!(core.doc().plain_text(), "brand new");
assert!(!core.can_undo(), "load must discard the prior undo history");
assert_eq!(core.caret(), DocPos::new(0, 0), "caret reset to document start");
}
#[test]
fn load_during_preview_abandons_session() {
let mut core = RichEditCore::new(RichDoc::from_blocks(vec![Block::plain("old")]), 16.0);
core.select_all();
core.begin_preview();
core.exec(&RichCommand::SetTextColor(Color::from_rgb8(255, 0, 0)));
assert!(core.is_previewing(), "preview active before load");
core.load(RichDoc::from_blocks(vec![Block::plain("brand new")]));
assert!(!core.is_previewing(), "load must end the preview session");
core.feed_undo(0.0);
core.select_all();
core.exec(&RichCommand::ToggleBold);
core.feed_undo(0.1);
core.feed_undo(2.0);
assert!(core.can_undo(), "undo must be functional after load-during-preview");
core.cancel_preview();
assert_eq!(
core.doc().plain_text(),
"brand new",
"cancel_preview after load must not clobber the loaded document"
);
}