Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
117 lines
5.6 KiB
Rust
117 lines
5.6 KiB
Rust
use super::input::open;
|
|
use super::layout::png;
|
|
use super::*;
|
|
use crate::menu::{self, Target};
|
|
|
|
pub(super) const DOC: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
|
|
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
|
|
<office:body><office:text><text:p>The cat ran.</text:p>
|
|
<table:table table:name="T"><table:table-column table:number-columns-repeated="2"/>
|
|
<table:table-row><table:table-cell><text:p>left</text:p></table:table-cell><table:table-cell><text:p>right</text:p></table:table-cell></table:table-row>
|
|
<table:table-row><table:table-cell><text:p>down</text:p></table:table-cell><table:table-cell><text:p>more</text:p></table:table-cell></table:table-row>
|
|
</table:table><text:p>after</text:p></office:text></office:body>
|
|
</office:document>"#;
|
|
|
|
const WAIT: std::time::Duration = std::time::Duration::from_secs(5);
|
|
|
|
/// Right-clicks at a point and reads the kernel's menu.
|
|
fn right(worker: &mut Worker, doc: &Doc, seen: &mut Events, (x, y): (i32, i32)) -> menu::Offered {
|
|
click(worker, doc, x, y);
|
|
press(worker, doc, seen, (x, y))
|
|
}
|
|
|
|
/// Right-clicks without moving the selection first.
|
|
fn press(worker: &mut Worker, doc: &Doc, seen: &mut Events, (x, y): (i32, i32)) -> menu::Offered {
|
|
for kind in [0, 1] {
|
|
let event = Mouse { kind, x, y, count: 1, buttons: 4, modifiers: 0 };
|
|
worker.post_mouse(doc, event).expect("the click posts");
|
|
}
|
|
*seen = poll_until(worker, doc, seen, WAIT, |seen| seen.menu.is_some());
|
|
menu::read(&seen.menu.take().expect("a menu")).expect("the menu parses")
|
|
}
|
|
|
|
/// The middle of the first match of `word`.
|
|
pub(super) fn find(worker: &mut Worker, doc: &Doc, seen: &mut Events, word: &str) -> (i32, i32) {
|
|
let before = seen.searched;
|
|
worker
|
|
.run(doc, "find.run", &[word, "false", "0", "0", "0", "1"])
|
|
.expect("the search runs");
|
|
*seen = poll_until(worker, doc, seen, WAIT, |seen| seen.searched > before);
|
|
let (x, y, _, h) = seen.found[0];
|
|
(x + 60, y + h / 2)
|
|
}
|
|
|
|
#[test]
|
|
fn a_right_click_names_its_target() {
|
|
if install().is_none() {
|
|
eprintln!("SKIP: no pinned LOK build");
|
|
return;
|
|
}
|
|
let (dir, mut worker, doc) = open(DOC);
|
|
click(&mut worker, &doc, 150, 150);
|
|
let mut seen = Events::default();
|
|
let at = find(&mut worker, &doc, &mut seen, "cat");
|
|
let text = right(&mut worker, &doc, &mut seen, at);
|
|
assert_eq!(text.target, Target::Text);
|
|
assert!(text.allows(".uno:InsertAnnotation") && text.allows(".uno:Paste"));
|
|
assert!(!text.allows(".uno:Cut"), "nothing is selected");
|
|
let at = find(&mut worker, &doc, &mut seen, "left");
|
|
let table = right(&mut worker, &doc, &mut seen, at);
|
|
assert_eq!(table.target, Target::Table);
|
|
for uno in [
|
|
".uno:InsertRowsBefore",
|
|
".uno:InsertColumnsAfter",
|
|
".uno:DeleteTable",
|
|
".uno:SplitCell",
|
|
] {
|
|
assert!(table.allows(uno), "{uno} runs in a cell");
|
|
}
|
|
assert!(!table.allows(".uno:MergeCells"), "one cell does not merge");
|
|
let at = find(&mut worker, &doc, &mut seen, "after");
|
|
click(&mut worker, &doc, at.0, at.1);
|
|
let blue = png(dir.path(), "blue.png", [0, 0, 255, 255]);
|
|
worker.run(&doc, "image.insert", &[&blue]).expect("the image lands");
|
|
seen = poll_until(&mut worker, &doc, &seen, WAIT, |seen| seen.graphic.is_some());
|
|
let (x, y, w, h) = seen.graphic.expect("the image is selected");
|
|
let frame = right(&mut worker, &doc, &mut seen, (x + w / 2, y + h / 2));
|
|
assert_eq!(frame.target, Target::Frame);
|
|
for uno in [".uno:Copy", ".uno:WrapOn", ".uno:BringToFront", ".uno:InsertCaptionDialog"] {
|
|
assert!(frame.allows(uno), "{uno} runs on an image");
|
|
}
|
|
assert!(!frame.allows(".uno:InsertAnnotation"), "no comment on an image");
|
|
}
|
|
|
|
const LOCKED: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
|
|
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
|
|
<office:body><office:text><text:p>open words</text:p>
|
|
<text:section text:name="S" text:protected="true"><text:p>sealed words</text:p></text:section>
|
|
<table:table table:name="T"><table:table-column table:number-columns-repeated="2"/>
|
|
<table:table-row><table:table-cell table:protected="true"><text:p>fixed</text:p></table:table-cell><table:table-cell><text:p>free</text:p></table:table-cell></table:table-row>
|
|
</table:table><text:p>after</text:p></office:text></office:body>
|
|
</office:document>"#;
|
|
|
|
#[test]
|
|
fn protected_text_offers_no_link() {
|
|
if install().is_none() {
|
|
eprintln!("SKIP: no pinned LOK build");
|
|
return;
|
|
}
|
|
let (_dir, mut worker, doc) = open(LOCKED);
|
|
click(&mut worker, &doc, 150, 150);
|
|
let mut seen = Events::default();
|
|
for (word, target, link) in [
|
|
("open", Target::Text, true),
|
|
("sealed", Target::Text, false),
|
|
("free", Target::Table, true),
|
|
("fixed", Target::Table, false),
|
|
] {
|
|
let at = find(&mut worker, &doc, &mut seen, word);
|
|
let offered = press(&mut worker, &doc, &mut seen, at);
|
|
assert_eq!(offered.target, target, "{word}");
|
|
assert_eq!(offered.allows(".uno:InsertHyperlink"), link, "{word} selected");
|
|
}
|
|
let at = find(&mut worker, &doc, &mut seen, "open");
|
|
let caret = right(&mut worker, &doc, &mut seen, at);
|
|
assert!(!caret.allows(".uno:InsertHyperlink"), "the kernel links a selection");
|
|
}
|