mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 21:44:57 +00:00
Merge pull request #7166 from dotCooCoo/fix/test-temp-folder-cleanup
Tests: ui-egui tests remove the temp folders they make
This commit is contained in:
@@ -33,11 +33,9 @@ fn hiding(hidden: &[(&str, &str)], readable: &[&str]) -> super::Hiding {
|
||||
|
||||
/// [`super::hide_library_ids`] on `reply`, under a read root made for `tag`.
|
||||
fn hide_under_a_root(tag: &str, reply: &mut Value, hidden: &super::Hiding) {
|
||||
let root = std::env::temp_dir().join(format!("vc-{tag}-root-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&root], &[]).unwrap();
|
||||
let root = crate::tests_folder::Folder::new(&format!("{tag}-root"));
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[root.as_path()], &[]).unwrap();
|
||||
vectorcraft_engine::file_access::confine(roots.as_ref(), || super::hide_library_ids(reply, hidden));
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
}
|
||||
|
||||
/// Encoded file data in a reply, a base64 string under `dataBase64`, `pngBase64`, `thumbnailBase64`
|
||||
@@ -73,7 +71,7 @@ fn a_reply_keeps_encoded_data_that_holds_a_hidden_path() {
|
||||
/// space do not keep it.
|
||||
#[test]
|
||||
fn a_reply_keeps_a_hidden_path_only_inside_a_known_library_id() {
|
||||
let base = std::env::temp_dir().join(format!("vc-continuation-{}", std::process::id()));
|
||||
let base = crate::tests_folder::Folder::new("continuation");
|
||||
let root = base.join("in");
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let hidden_path = base.join("in x").join("b.svg").to_string_lossy().into_owned();
|
||||
@@ -84,7 +82,6 @@ fn a_reply_keeps_a_hidden_path_only_inside_a_known_library_id() {
|
||||
let mut reply = json!({"error": format!("kept {hidden_path}.bak, {other}{up} and {known}")});
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&root], &[]).unwrap();
|
||||
vectorcraft_engine::file_access::confine(roots.as_ref(), || super::hide_library_ids(&mut reply, &hidden));
|
||||
let _ = std::fs::remove_dir_all(base);
|
||||
assert_eq!(reply["error"], json!(format!("kept b.svg.bak, b.svg (2){up} and {known}")), "{reply}");
|
||||
// A readable library's id with a space after the hidden part stays whole.
|
||||
// A readable id with a `..` part does not keep the hidden part.
|
||||
@@ -250,7 +247,7 @@ fn a_reply_hides_a_hidden_relative_path_written_as_absolute() {
|
||||
/// by their file names; plain text and a path inside the root are not.
|
||||
#[test]
|
||||
fn a_request_sends_paths_that_an_error_hides() {
|
||||
let base = std::env::temp_dir().join(format!("vc-sent-paths-{}", std::process::id()));
|
||||
let base = crate::tests_folder::Folder::new("sent-paths");
|
||||
let root = base.join("in");
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let inside = root.join("a.svg").to_string_lossy().into_owned();
|
||||
@@ -259,7 +256,6 @@ fn a_request_sends_paths_that_an_error_hides() {
|
||||
let mut sent = Vec::new();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&root], &[]).unwrap();
|
||||
vectorcraft_engine::file_access::confine(roots.as_ref(), || super::sent_paths(¶ms, &mut sent));
|
||||
let _ = std::fs::remove_dir_all(base);
|
||||
let pair = |path: &str, name: &str| (format!("loaded/{path}"), format!("loaded/{name}"));
|
||||
let want = [
|
||||
pair("outside/h.svg", "h.svg"),
|
||||
@@ -276,7 +272,7 @@ fn a_request_sends_paths_that_an_error_hides() {
|
||||
/// relative name and a path inside the root are not.
|
||||
#[test]
|
||||
fn an_absolute_path_outside_the_read_root_is_unreadable() {
|
||||
let base = std::env::temp_dir().join(format!("vc-unreadable-absolute-{}", std::process::id()));
|
||||
let base = crate::tests_folder::Folder::new("unreadable-absolute");
|
||||
std::fs::create_dir_all(base.join("in")).unwrap();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&base.join("in")], &[]).unwrap();
|
||||
let inside = base.join("in").join("a.svg").to_string_lossy().into_owned();
|
||||
@@ -295,7 +291,6 @@ fn an_absolute_path_outside_the_read_root_is_unreadable() {
|
||||
assert!(!super::unreadable_absolute("keep"));
|
||||
assert!(!super::unreadable_absolute(&inside));
|
||||
});
|
||||
let _ = std::fs::remove_dir_all(base);
|
||||
}
|
||||
|
||||
/// Without a read root, a `file:` URL that names another host may be read, and a recorded step keeps
|
||||
@@ -395,12 +390,10 @@ fn a_reply_keeps_a_longer_path_that_ends_with_a_hidden_relative_path() {
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn a_sent_path_keeps_a_backslash_in_its_file_name() {
|
||||
let root = std::env::temp_dir().join(format!("vc-sent-backslash-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&root], &[]).unwrap();
|
||||
let root = crate::tests_folder::Folder::new("sent-backslash");
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[root.as_path()], &[]).unwrap();
|
||||
let mut sent = Vec::new();
|
||||
vectorcraft_engine::file_access::confine(roots.as_ref(), || super::sent_paths(&json!({"path": "/out/weird\\name.svg"}), &mut sent));
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
assert_eq!(sent, [("loaded//out/weird\\name.svg".to_string(), "loaded/weird\\name.svg".to_string())]);
|
||||
}
|
||||
|
||||
@@ -412,13 +405,11 @@ fn a_hidden_library_at_the_top_of_the_file_system_keeps_its_shown_id() {
|
||||
let panel = "library:swatches:loaded//b.svg".to_string();
|
||||
app.ui.color_guide_limit = "loaded//b.svg".to_string();
|
||||
app.ui.open_panel = Some(panel);
|
||||
let root = std::env::temp_dir().join(format!("vc-top-level-library-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&root], &[]).unwrap();
|
||||
let root = crate::tests_folder::Folder::new("top-level-library");
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[root.as_path()], &[]).unwrap();
|
||||
let (inspected, docking) = vectorcraft_engine::file_access::confine(roots.as_ref(), || {
|
||||
(input_request(&mut app, "ui.inspect", json!({})), input_request(&mut app, "ui.docking", json!({})))
|
||||
});
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
assert_eq!(inspected["result"]["ui"]["color_guide_limit"], "loaded/b.svg", "{inspected}");
|
||||
assert_eq!(inspected["result"]["ui"]["open_panel"], "library:swatches:loaded/b.svg", "{inspected}");
|
||||
assert_eq!(docking["result"]["flyout"], "library:swatches:loaded/b.svg", "{docking}");
|
||||
@@ -429,9 +420,8 @@ fn a_hidden_library_at_the_top_of_the_file_system_keeps_its_shown_id() {
|
||||
#[test]
|
||||
fn a_sent_path_reads_the_same_whatever_the_outcome() {
|
||||
let app = VectorcraftApp::new(Session::new(), Services::default());
|
||||
let root = std::env::temp_dir().join(format!("vc-sent-outcome-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[&root], &[]).unwrap();
|
||||
let root = crate::tests_folder::Folder::new("sent-outcome");
|
||||
let roots = vectorcraft_engine::file_access::AutomationRoots::new(&[root.as_path()], &[]).unwrap();
|
||||
let sent = json!({"path": "/outside/b.svg"});
|
||||
let mut done = json!({"ok": true, "result": {"path": "/outside/b.svg"}});
|
||||
let mut failed = json!({"ok": false, "error": "can't read /outside/b.svg"});
|
||||
@@ -439,7 +429,6 @@ fn a_sent_path_reads_the_same_whatever_the_outcome() {
|
||||
super::hide_in_reply(&app, &mut done, &sent, super::Hiding::default());
|
||||
super::hide_in_reply(&app, &mut failed, &sent, super::Hiding::default());
|
||||
});
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
assert_eq!(done["result"]["path"], "b.svg", "{done}");
|
||||
assert_eq!(failed["error"], "can't read b.svg", "{failed}");
|
||||
}
|
||||
@@ -1157,7 +1146,7 @@ fn panels_that_redraw_apply_a_merge_on_another_thread_first() {
|
||||
/// applies the merge first: the file holds it, and closing asks to save it.
|
||||
#[test]
|
||||
fn save_and_close_apply_a_merge_on_another_thread_first() {
|
||||
let dir = vectorcraft_testkit::temp_dir("control-merge-save");
|
||||
let dir = crate::tests_folder::Folder::adopt(vectorcraft_testkit::temp_dir("control-merge-save"));
|
||||
for then in ["file.saveAs", "file.exportAs", "file.close"] {
|
||||
let services = Services { write: Some(Box::new(|p: &str, b: &[u8]| std::fs::write(p, b).map_err(|e| e.to_string()))), ..Default::default() };
|
||||
let mut app = VectorcraftApp::new(Session::new(), services);
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
use std::time::Instant;
|
||||
|
||||
use vectorcraft_engine::Session;
|
||||
use vectorcraft_engine::cmd::findfiles::Rules;
|
||||
|
||||
use super::*;
|
||||
use crate::tests_folder::Folder;
|
||||
|
||||
fn frame(app: &mut VectorcraftApp) -> String {
|
||||
crate::tests_labels::painted_text(app, |app, ui| super::super::show(app, ui.ctx()))
|
||||
}
|
||||
|
||||
/// A fresh temporary folder (canonical, as a search reports it).
|
||||
fn folder(tag: &str) -> PathBuf {
|
||||
/// A fresh temporary folder (canonical, as a search reports it), removed when dropped.
|
||||
fn folder(tag: &str) -> Folder {
|
||||
let dir = vectorcraft_testkit::temp_dir(&format!("missing-fonts-{tag}"));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
vectorcraft_engine::cmd::findfiles::plain(std::fs::canonicalize(&dir).unwrap())
|
||||
Folder::adopt(vectorcraft_engine::cmd::findfiles::plain(std::fs::canonicalize(&dir).unwrap()))
|
||||
}
|
||||
|
||||
/// An app that reads files and whose searches may go anywhere in `root`, on two threads.
|
||||
@@ -191,7 +190,7 @@ fn closing_the_dialog_stops_its_search() {
|
||||
app.session.search_threads = Some(1);
|
||||
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
|
||||
app.run("text.create", json!({"x": 10, "y": 40, "text": "Gone", "font": "No Such Font Family"})).unwrap();
|
||||
app.run("ui.missingFontsDialog", json!({"folder": root})).unwrap();
|
||||
app.run("ui.missingFontsDialog", json!({"folder": root.as_path()})).unwrap();
|
||||
let id = app.ui.dialog_search.expect("the dialog's search");
|
||||
super::super::cancel(&mut app);
|
||||
assert!(app.ui.dialog.is_none() && app.ui.dialog_search.is_none());
|
||||
@@ -275,7 +274,8 @@ fn the_question_comes_back_after_a_dialog_that_took_its_place() {
|
||||
/// opens without the question.
|
||||
#[test]
|
||||
fn generic_families_are_not_asked_about() {
|
||||
let mut app = app_for(&folder("generic"));
|
||||
let root = folder("generic");
|
||||
let mut app = app_for(&root);
|
||||
let svg = r#"<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><text x="10" y="40" font-family="sans-serif">A</text></svg>"#;
|
||||
crate::io::open_bytes(&mut app, "generic.svg", svg.as_bytes(), None).unwrap();
|
||||
let listed = app.session.execute("text.fonts", &json!({})).unwrap();
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::rc::Rc;
|
||||
use vectorcraft_engine::Session;
|
||||
|
||||
use super::*;
|
||||
use crate::tests_folder::Folder;
|
||||
use crate::{FilePick, Services, theme};
|
||||
|
||||
type Written = Rc<RefCell<Vec<(String, Vec<u8>)>>>;
|
||||
@@ -197,7 +198,7 @@ fn board_files_of(app: &VectorcraftApp, boards: [bool; 4]) -> Vec<Option<String>
|
||||
#[test]
|
||||
fn the_enter_that_closed_the_save_panel_does_not_confirm_the_options() {
|
||||
let (mut app, written, _) = desktop("again.ai");
|
||||
let dir = vectorcraft_testkit::temp_dir("ai-options-enter");
|
||||
let dir = Folder::adopt(vectorcraft_testkit::temp_dir("ai-options-enter"));
|
||||
let orig = dir.join("orig.ai");
|
||||
std::fs::write(&orig, vectorcraft_testkit::ai::ai(&vectorcraft_testkit::ai::sample_data(), vectorcraft_testkit::ai::page_pdf())).unwrap();
|
||||
app.run("document.open", json!({"path": orig.to_string_lossy()})).unwrap();
|
||||
@@ -215,7 +216,7 @@ fn the_enter_that_closed_the_save_panel_does_not_confirm_the_options() {
|
||||
#[test]
|
||||
fn save_a_copy_and_template_suggest_their_names() {
|
||||
let (mut app, written, picks) = desktop("copy.vectorcraft");
|
||||
let folder = vectorcraft_testkit::temp_dir("save-template-dialog");
|
||||
let folder = Folder::adopt(vectorcraft_testkit::temp_dir("save-template-dialog"));
|
||||
app.session.prefs.templates_folder = folder.to_string_lossy().into_owned();
|
||||
app.run("file.saveCopy", json!({})).unwrap();
|
||||
assert_eq!(picks.borrow()[0].name, "Untitled-1 copy.vectorcraft");
|
||||
@@ -237,7 +238,8 @@ fn save_a_copy_and_template_suggest_their_names() {
|
||||
#[test]
|
||||
fn save_as_template_writes_ait_when_it_is_picked() {
|
||||
let (mut app, written, _) = desktop("flyer.ait");
|
||||
app.session.prefs.templates_folder = vectorcraft_testkit::temp_dir("save-template-ait").to_string_lossy().into_owned();
|
||||
let folder = Folder::adopt(vectorcraft_testkit::temp_dir("save-template-ait"));
|
||||
app.session.prefs.templates_folder = folder.to_string_lossy().into_owned();
|
||||
app.run("file.saveAsTemplate", json!({})).unwrap();
|
||||
assert!(app.ui.dialog.is_none(), "a template asks no options");
|
||||
let (path, bytes) = written.borrow()[0].clone();
|
||||
@@ -285,9 +287,10 @@ fn the_native_options_have_no_precision_row() {
|
||||
/// replaced with the template's, as Save As replaces the extension of a format it doesn't write.
|
||||
#[test]
|
||||
fn save_as_template_replaces_a_save_formats_extension() {
|
||||
let folder = Folder::adopt(vectorcraft_testkit::temp_dir("save-template-ext"));
|
||||
for (picked, saved) in [("card.pdf", "card.vctemplate"), ("card.vectorcraft", "card.vctemplate"), ("card.svg", "card.vctemplate")] {
|
||||
let (mut app, written, _) = desktop(picked);
|
||||
app.session.prefs.templates_folder = vectorcraft_testkit::temp_dir("save-template-ext").to_string_lossy().into_owned();
|
||||
app.session.prefs.templates_folder = folder.to_string_lossy().into_owned();
|
||||
app.run("file.saveAsTemplate", json!({})).unwrap();
|
||||
let (path, bytes) = written.borrow()[0].clone();
|
||||
assert_eq!(path, saved, "typed {picked}");
|
||||
|
||||
@@ -91,8 +91,8 @@ pub mod workspaces;
|
||||
mod document_drag;
|
||||
#[cfg(test)]
|
||||
use tests::{
|
||||
background as tests_background, labels as tests_labels, picks as tests_picks, removeanchors as tests_removeanchors, svg as tests_svg,
|
||||
synthetic as tests_synthetic, sysclip as tests_sysclip,
|
||||
background as tests_background, folder as tests_folder, labels as tests_labels, picks as tests_picks, removeanchors as tests_removeanchors,
|
||||
svg as tests_svg, synthetic as tests_synthetic, sysclip as tests_sysclip,
|
||||
};
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -56,13 +56,9 @@ fn install_importer(app: &mut VectorcraftApp, src: &str) {
|
||||
}
|
||||
|
||||
/// A file for the importers below, in a folder of its own.
|
||||
fn importer_file(tag: &str) -> (std::path::PathBuf, String) {
|
||||
let dir = std::env::temp_dir().join(format!("vc-ui-opening-{tag}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let file = dir.join("a.tob");
|
||||
std::fs::write(&file, "not json").unwrap();
|
||||
let file = file.to_string_lossy().into_owned();
|
||||
fn importer_file(tag: &str) -> (crate::tests_folder::Folder, String) {
|
||||
let dir = crate::tests_folder::Folder::new(&format!("ui-opening-{tag}"));
|
||||
let file = dir.file("a.tob", b"not json");
|
||||
(dir, file)
|
||||
}
|
||||
|
||||
@@ -73,7 +69,7 @@ fn importer_file(tag: &str) -> (std::path::PathBuf, String) {
|
||||
fn open_with_runs_the_importer_off_the_ui_thread() {
|
||||
use vectorcraft_plugins::wat::{self as tpl, Given};
|
||||
let rect = r#"{"objects":[{"type":"path","path":{"subpaths":[{"closed":true,"anchors":[{"p":[10,20]},{"p":[110,20]},{"p":[110,70]},{"p":[10,70]}]}]}}]}"#;
|
||||
let (dir, file) = importer_file("with");
|
||||
let (_dir, file) = importer_file("with");
|
||||
let mut app = VectorcraftApp::new(Session::new(), Services::default());
|
||||
app.services.read = Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string())));
|
||||
let params = r#"{"density":{"type":"number","min":0,"max":10,"default":4}}"#;
|
||||
@@ -97,14 +93,13 @@ fn open_with_runs_the_importer_off_the_ui_thread() {
|
||||
assert!(app.ui.dialog.is_some(), "the failure is reported in a dialog");
|
||||
assert!(app.ui.recent_files.is_empty());
|
||||
app.run("plugin.remove", json!({"id": "test.opening.with"})).unwrap();
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// Cancel stops an importer that never returns, on the thread reading the file.
|
||||
#[test]
|
||||
fn cancel_stops_a_running_importer() {
|
||||
use vectorcraft_plugins::wat as tpl;
|
||||
let (dir, file) = importer_file("cancel");
|
||||
let (_dir, file) = importer_file("cancel");
|
||||
let mut app = VectorcraftApp::new(Session::new(), Services::default());
|
||||
app.services.read = Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string())));
|
||||
install_importer(&mut app, &tpl::module(&tpl::importer("test.opening.spins", r#"["tob"]"#, "{}"), "(loop $l (br $l)) (i64.const 0)", "", 1));
|
||||
@@ -115,7 +110,6 @@ fn cancel_stops_a_running_importer() {
|
||||
assert!(r.as_ref().err().is_some_and(|e| e.contains("cancelled")), "{:?}", r.err());
|
||||
assert!(app.session.documents().is_empty());
|
||||
app.run("plugin.remove", json!({"id": "test.opening.spins"})).unwrap();
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// #1694: a file that finishes opening while a dialog is up waits for it to close, so the
|
||||
@@ -289,8 +283,7 @@ fn a_file_read_off_the_ui_thread_opens_as_one_read_at_once() {
|
||||
#[test]
|
||||
fn a_file_read_off_the_ui_thread_has_its_links_and_type_as_one_read_at_once() {
|
||||
use image::ImageFormat::{Bmp, Jpeg, Png, Tiff};
|
||||
let dir = std::env::temp_dir().join(format!("vc-opening-links-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let dir = crate::tests_folder::Folder::new("opening-links");
|
||||
let (before, after) = (dir.join("before"), dir.join("after"));
|
||||
std::fs::create_dir_all(&before).unwrap();
|
||||
let file = |folder: &std::path::Path, name: &str| folder.join(name).to_string_lossy().into_owned();
|
||||
@@ -336,7 +329,6 @@ fn a_file_read_off_the_ui_thread_has_its_links_and_type_as_one_read_at_once() {
|
||||
assert!(st.history.undo.is_empty() && !st.is_dirty(), "{update}");
|
||||
assert_eq!(asked(&app), question, "{update}");
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// A file opened under automation roots is installed under them too: the open keeps the scope it
|
||||
@@ -344,7 +336,7 @@ fn a_file_read_off_the_ui_thread_has_its_links_and_type_as_one_read_at_once() {
|
||||
#[test]
|
||||
fn a_file_opened_under_automation_roots_finishes_under_them() {
|
||||
use vectorcraft_engine::file_access;
|
||||
let dir = scope_dir();
|
||||
let dir = crate::tests_folder::Folder::new("opening-scope");
|
||||
let roots = file_access::AutomationRoots::new(&[dir.as_path()], &[]).unwrap();
|
||||
let mut app = VectorcraftApp::new(Session::new(), Services::default());
|
||||
file_access::confine(roots.as_ref(), || {
|
||||
@@ -355,12 +347,6 @@ fn a_file_opened_under_automation_roots_finishes_under_them() {
|
||||
assert!(scope.run(file_access::current).is_some(), "the roots go with the open");
|
||||
}
|
||||
|
||||
fn scope_dir() -> std::path::PathBuf {
|
||||
let dir = std::env::temp_dir().join(format!("vectorcraft-opening-scope-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
dir
|
||||
}
|
||||
|
||||
/// A file asked for again while it is still being read is not read a second time (#3455).
|
||||
#[test]
|
||||
fn a_file_asked_for_again_while_it_is_read_opens_once() {
|
||||
@@ -378,9 +364,7 @@ fn a_file_asked_for_again_while_it_is_read_opens_once() {
|
||||
/// the dialog acts on its own document (#5369).
|
||||
#[test]
|
||||
fn a_queued_reopen_that_asks_holds_back_files_ready_to_open() {
|
||||
let dir = std::env::temp_dir().join(format!("vectorcraft-opening-queued-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let dir = crate::tests_folder::Folder::new("opening-queued");
|
||||
let mut app = VectorcraftApp::new(Session::new(), Services::default());
|
||||
app.services.read = Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string())));
|
||||
let (doc, other) = (dir.join("doc.vectorcraft"), dir.join("other.vectorcraft"));
|
||||
@@ -407,7 +391,6 @@ fn a_queued_reopen_that_asks_holds_back_files_ready_to_open() {
|
||||
assert_eq!(app.session.doc().unwrap().path.as_deref(), Some(&*doc), "the dialog's document stays active");
|
||||
assert_eq!(app.opening.activate.first().map(|(p, _)| p), Some(&other), "the later activation waits");
|
||||
assert_eq!(app.opening.pending.len(), 1, "the other file waits");
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
/// Of two files read off the UI thread and ready in the same frame, the first that opens and asks
|
||||
|
||||
@@ -8,6 +8,7 @@ mod cut;
|
||||
mod distortkeys;
|
||||
mod docsetup;
|
||||
mod document_drag;
|
||||
pub(super) mod folder;
|
||||
mod font_menu;
|
||||
mod fonts;
|
||||
mod guide_escape;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
//! A test's temporary folder, removed with everything in it when the test ends.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// A test's folder, removed with everything in it when dropped, also when the test panics, as
|
||||
/// the engine's find-files tests remove their trees. A removal that fails (a file still held open)
|
||||
/// is ignored.
|
||||
pub(crate) struct Folder(PathBuf);
|
||||
|
||||
impl Folder {
|
||||
/// A new empty folder `vectorcraft-<name>-<process id>` in the system temporary folder. One
|
||||
/// left there by an earlier process with the same id is removed first.
|
||||
pub(crate) fn new(name: &str) -> Self {
|
||||
let dir = std::env::temp_dir().join(format!("vectorcraft-{name}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
Self(dir)
|
||||
}
|
||||
|
||||
/// The folder at `dir`, made by the caller, removed when dropped.
|
||||
pub(crate) fn adopt(dir: PathBuf) -> Self {
|
||||
Self(dir)
|
||||
}
|
||||
|
||||
/// `bytes` written to a file `name` in the folder → its path.
|
||||
pub(crate) fn file(&self, name: &str, bytes: &[u8]) -> String {
|
||||
let path = self.0.join(name);
|
||||
std::fs::write(&path, bytes).unwrap();
|
||||
path.to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Folder {
|
||||
type Target = PathBuf;
|
||||
fn deref(&self) -> &PathBuf {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Folder {
|
||||
fn drop(&mut self) {
|
||||
let _ = std::fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_folder_is_removed_when_its_test_ends() {
|
||||
let folder = Folder::new("ui-folder-ends");
|
||||
let path = folder.to_path_buf();
|
||||
std::fs::create_dir_all(path.join("nested")).unwrap();
|
||||
folder.file("nested/a.txt", b"a");
|
||||
assert!(path.join("nested").join("a.txt").is_file());
|
||||
drop(folder);
|
||||
assert!(!path.exists(), "{} is left", path.display());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_folder_is_removed_when_its_test_panics() {
|
||||
let path = std::env::temp_dir().join(format!("vectorcraft-ui-folder-panics-{}", std::process::id()));
|
||||
let r = vectorcraft_testkit::catch_quiet::<()>(|| {
|
||||
let folder = Folder::new("ui-folder-panics");
|
||||
folder.file("a.txt", b"a");
|
||||
panic!("the test fails");
|
||||
});
|
||||
assert_eq!(r.err().as_deref(), Some("the test fails"));
|
||||
assert!(!path.exists(), "{} is left", path.display());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_adopted_test_kit_folder_is_removed_when_its_test_ends() {
|
||||
let folder = Folder::adopt(vectorcraft_testkit::temp_dir("ui-folder-adopted"));
|
||||
let path = folder.to_path_buf();
|
||||
folder.file("a.txt", b"a");
|
||||
drop(folder);
|
||||
assert!(!path.exists(), "{} is left", path.display());
|
||||
}
|
||||
@@ -11,6 +11,7 @@ use vectorcraft_engine::Session;
|
||||
use crate::VectorcraftApp;
|
||||
use crate::canvas::Xf;
|
||||
use crate::place::{DropAt, DropTarget};
|
||||
use crate::tests_folder::Folder;
|
||||
|
||||
/// A `w`×`h` red PNG declaring `ppi`.
|
||||
fn png(w: u32, h: u32, ppi: f64) -> Vec<u8> {
|
||||
@@ -19,15 +20,6 @@ fn png(w: u32, h: u32, ppi: f64) -> Vec<u8> {
|
||||
vectorcraft_engine::cmd::fileio::ppi::with_png_resolution(&out, (ppi, ppi))
|
||||
}
|
||||
|
||||
/// `bytes` written to a fresh temporary file named `name` → its path.
|
||||
fn temp_file(name: &str, bytes: &[u8]) -> String {
|
||||
let dir = std::env::temp_dir().join(format!("vectorcraft-ui-place-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let path = dir.join(name);
|
||||
std::fs::write(&path, bytes).unwrap();
|
||||
path.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
/// An app reading files from disk, with a 400×300 document.
|
||||
fn app() -> VectorcraftApp {
|
||||
let services = crate::Services { read: Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string()))), ..Default::default() };
|
||||
@@ -166,7 +158,8 @@ fn a_dropped_swatch_library_opens_in_the_library_panel() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let gpl = temp_file("dropped.gpl", b"GIMP Palette\nName: Dropped\n#\n255 0 0\tRed\n 0 128 255\tSky\n");
|
||||
let dir = Folder::new("ui-place-swatches");
|
||||
let gpl = dir.file("dropped.gpl", b"GIMP Palette\nName: Dropped\n#\n255 0 0\tRed\n 0 128 255\tSky\n");
|
||||
frame(&mut app, &ctx, vec![], &[&gpl], false);
|
||||
let id = format!("loaded/{gpl}");
|
||||
assert_eq!(crate::panels::library_panel::last_open(&app.ui).map(|o| o.id.as_str()), Some(id.as_str()), "{}", app.ui.status);
|
||||
@@ -184,7 +177,8 @@ fn a_dropped_script_shows_its_check() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let path = temp_file("dropped.jsx", b"#target acme\napp.executeMenuCommand('acmecopyall');\n");
|
||||
let dir = Folder::new("ui-place-script");
|
||||
let path = dir.file("dropped.jsx", b"#target acme\napp.executeMenuCommand('acmecopyall');\n");
|
||||
frame(&mut app, &ctx, vec![], &[&path], false);
|
||||
let d = app.ui.dialog.as_ref().expect("the check is shown");
|
||||
assert_eq!(d.kind, crate::dialogs::script_check::KIND, "{}", app.ui.status);
|
||||
@@ -203,7 +197,8 @@ fn a_dropped_libraries_panel_file_is_added_as_a_new_library() {
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let file = json!({"name": "Dropped", "colors": [{"name": "Red", "color": {"model": "rgb", "r": 1, "g": 0, "b": 0}}]});
|
||||
let path = temp_file("dropped.vclibrary", file.to_string().as_bytes());
|
||||
let dir = Folder::new("ui-place-library");
|
||||
let path = dir.file("dropped.vclibrary", file.to_string().as_bytes());
|
||||
frame(&mut app, &ctx, vec![], &[&path], false);
|
||||
assert_eq!(app.ui.status, "Imported library Dropped");
|
||||
let lib = app.session.execute("library.get", &json!({})).unwrap();
|
||||
@@ -220,7 +215,8 @@ fn a_dropped_shortcut_set_opens_import_shortcut_set() {
|
||||
let ctx = egui::Context::default();
|
||||
let rect = laid_out(&mut app, &ctx);
|
||||
let set = "/Menus {\n /Acme\\ Undo { /Modifiers 11 /Key 902 }\n}\n";
|
||||
let path = temp_file("dropped.kys", set.as_bytes());
|
||||
let dir = Folder::new("ui-place-shortcuts");
|
||||
let path = dir.file("dropped.kys", set.as_bytes());
|
||||
frame(&mut app, &ctx, vec![], &[&path], false);
|
||||
let kind = |app: &VectorcraftApp| app.ui.dialog.as_ref().map(|d| d.kind.clone());
|
||||
assert_eq!(kind(&app).as_deref(), Some(crate::dialogs::shortcut_import::KIND), "{}", app.ui.status);
|
||||
@@ -237,7 +233,8 @@ fn a_dropped_png_is_placed_in_the_middle_of_the_view() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let path = temp_file("drop.png", &png(20, 10, 72.0));
|
||||
let dir = Folder::new("ui-place-png");
|
||||
let path = dir.file("drop.png", &png(20, 10, 72.0));
|
||||
// Where egui last saw the pointer is stale during a desktop drag: it doesn't count.
|
||||
frame(&mut app, &ctx, vec![egui::Event::PointerMoved(Pos2::new(5.0, 5.0))], &[&path], false);
|
||||
let n = selected_image(&app);
|
||||
@@ -258,8 +255,9 @@ fn a_dropped_document_opens_as_a_tab_of_its_own() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let svg = temp_file("dropped.svg", SVG.as_bytes());
|
||||
let pic = temp_file("with-it.png", &png(8, 8, 72.0));
|
||||
let dir = Folder::new("ui-place-tab");
|
||||
let svg = dir.file("dropped.svg", SVG.as_bytes());
|
||||
let pic = dir.file("with-it.png", &png(8, 8, 72.0));
|
||||
frame(&mut app, &ctx, vec![], &[&svg, &pic], false);
|
||||
assert_eq!(app.session.documents().len(), 2, "opened, not placed");
|
||||
assert_eq!(app.session.active_index(), Some(1), "the document opened is shown");
|
||||
@@ -270,7 +268,8 @@ fn a_dropped_document_opens_as_a_tab_of_its_own() {
|
||||
|
||||
#[test]
|
||||
fn a_native_svg_drop_uses_file_open_even_with_a_path_only_handle() {
|
||||
let path = temp_file("path-only.svg", SVG.as_bytes());
|
||||
let dir = Folder::new("ui-place-path-only");
|
||||
let path = dir.file("path-only.svg", SVG.as_bytes());
|
||||
let mut dropped = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut dropped, &ctx);
|
||||
@@ -317,8 +316,9 @@ fn multiple_svg_drops_open_individually() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let a = temp_file("first.svg", SVG.as_bytes());
|
||||
let b = temp_file("second.svg", SVG.as_bytes());
|
||||
let dir = Folder::new("ui-place-several-svg");
|
||||
let a = dir.file("first.svg", SVG.as_bytes());
|
||||
let b = dir.file("second.svg", SVG.as_bytes());
|
||||
frame(&mut app, &ctx, vec![], &[&a, &b], false);
|
||||
assert_eq!(app.session.documents().len(), 3);
|
||||
assert_eq!(app.session.active().unwrap().path.as_deref(), Some(b.as_str()));
|
||||
@@ -330,15 +330,16 @@ fn unsupported_and_unreadable_drops_leave_the_document_open() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
laid_out(&mut app, &ctx);
|
||||
let invalid = temp_file("not-art.xyz", b"not an image or document");
|
||||
let dir = Folder::new("ui-place-unreadable");
|
||||
let invalid = dir.file("not-art.xyz", b"not an image or document");
|
||||
frame(&mut app, &ctx, vec![], &[&invalid], false);
|
||||
assert!(app.ui.status.contains("Couldn't place not-art.xyz"), "{}", app.ui.status);
|
||||
|
||||
let invalid_svg = temp_file("broken.svg", b"<svg");
|
||||
let invalid_svg = dir.file("broken.svg", b"<svg");
|
||||
frame(&mut app, &ctx, vec![], &[&invalid_svg], false);
|
||||
assert!(app.ui.status.contains("Couldn't open broken.svg"), "{}", app.ui.status);
|
||||
|
||||
let missing = temp_file("unreadable.svg", SVG.as_bytes());
|
||||
let missing = dir.file("unreadable.svg", SVG.as_bytes());
|
||||
std::fs::remove_file(&missing).unwrap();
|
||||
frame(&mut app, &ctx, vec![], &[&missing], false);
|
||||
assert!(app.ui.status.contains("Couldn't open unreadable.svg"), "{}", app.ui.status);
|
||||
@@ -350,7 +351,8 @@ fn unsupported_and_unreadable_drops_leave_the_document_open() {
|
||||
fn files_dropped_with_no_document_open_open_and_are_recent() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
let ctx = egui::Context::default();
|
||||
let path = temp_file("open-me.png", &png(8, 8, 72.0));
|
||||
let dir = Folder::new("ui-place-no-document");
|
||||
let path = dir.file("open-me.png", &png(8, 8, 72.0));
|
||||
frame(&mut app, &ctx, vec![], &[], false);
|
||||
frame(&mut app, &ctx, vec![], &[&path], false);
|
||||
assert_eq!(app.session.documents().len(), 1, "no document: the drop opens");
|
||||
@@ -407,8 +409,9 @@ fn a_file_read_after_another_document_became_active_lands_where_it_was_dropped()
|
||||
#[test]
|
||||
fn the_place_dialog_lists_the_files_and_loads_the_cursor_with_several() {
|
||||
let mut app = app();
|
||||
let a = temp_file("a.png", &png(300, 150, 300.0));
|
||||
let b = temp_file("b.png", &png(10, 10, 72.0));
|
||||
let dir = Folder::new("ui-place-dialog");
|
||||
let a = dir.file("a.png", &png(300, 150, 300.0));
|
||||
let b = dir.file("b.png", &png(10, 10, 72.0));
|
||||
app.run("file.place", json!({"paths": [a, b]})).unwrap();
|
||||
let d = app.ui.dialog.as_ref().expect("the Place dialog");
|
||||
assert_eq!(d.kind, crate::dialogs::place::KIND);
|
||||
@@ -448,7 +451,8 @@ fn the_place_dialog_lists_the_files_and_loads_the_cursor_with_several() {
|
||||
fn one_file_places_centred_in_the_view_and_replace_swaps_the_selection() {
|
||||
let mut app = app();
|
||||
app.view_mut().unwrap().center = vectorcraft_geom::Point::new(120.0, 80.0);
|
||||
place_picked(&mut app, &temp_file("one.png", &png(300, 150, 300.0)));
|
||||
let dir = Folder::new("ui-place-replace");
|
||||
place_picked(&mut app, &dir.file("one.png", &png(300, 150, 300.0)));
|
||||
let d = app.ui.dialog.as_ref().expect("the Place dialog");
|
||||
assert_eq!(d.kind, crate::dialogs::place::KIND);
|
||||
assert!(d.bool("link") && !d.bool("__replace"), "Link on; Replace needs one selected object");
|
||||
@@ -462,7 +466,7 @@ fn one_file_places_centred_in_the_view_and_replace_swaps_the_selection() {
|
||||
let first = selected_image(&app);
|
||||
assert_eq!(first.geometric_bounds().unwrap().center(), vectorcraft_geom::Point::new(120.0, 80.0), "centred in the view");
|
||||
// With one object selected, Replace applies.
|
||||
place_picked(&mut app, &temp_file("two.png", &png(40, 40, 144.0)));
|
||||
place_picked(&mut app, &dir.file("two.png", &png(40, 40, 144.0)));
|
||||
assert!(app.ui.dialog.as_ref().unwrap().bool("__replace"));
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("replace".into(), json!(true));
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("link".into(), json!(false));
|
||||
@@ -476,7 +480,8 @@ fn one_file_places_centred_in_the_view_and_replace_swaps_the_selection() {
|
||||
#[test]
|
||||
fn the_control_bar_shows_the_image_file_link_colour_mode_and_ppi() {
|
||||
let mut app = app();
|
||||
let path = temp_file("photo.png", &png(30, 30, 300.0));
|
||||
let dir = Folder::new("ui-place-control-bar");
|
||||
let path = dir.file("photo.png", &png(30, 30, 300.0));
|
||||
app.run("file.place", json!({"path": path})).unwrap();
|
||||
let text = crate::tests_labels::painted_text(&mut app, crate::chrome::control_bar);
|
||||
for s in ["Linked File", "photo.png", "RGB PPI: 300"] {
|
||||
@@ -493,7 +498,8 @@ fn the_control_bar_shows_the_image_file_link_colour_mode_and_ppi() {
|
||||
#[test]
|
||||
fn the_control_bar_label_follows_edits_undo_documents_and_selection() {
|
||||
let mut app = app();
|
||||
let path = temp_file("label.png", &png(30, 30, 72.0));
|
||||
let dir = Folder::new("ui-place-label");
|
||||
let path = dir.file("label.png", &png(30, 30, 72.0));
|
||||
app.run("file.place", json!({"path": path})).unwrap();
|
||||
let text = |app: &mut VectorcraftApp| crate::tests_labels::painted_text(app, crate::chrome::control_bar);
|
||||
assert!(text(&mut app).contains("Linked File"));
|
||||
@@ -539,7 +545,8 @@ fn the_control_bars_file_name_relinks_the_image() {
|
||||
for s in ["Replace…", "Go To Link", "Edit Original", "Update Link", "Placement Options…"] {
|
||||
item(&mut app, &ctx, s);
|
||||
}
|
||||
let other = temp_file("blue.png", &png(60, 30, 72.0));
|
||||
let dir = Folder::new("ui-place-relink");
|
||||
let other = dir.file("blue.png", &png(60, 30, 72.0));
|
||||
let picked = other.clone();
|
||||
app.services.pick_open = Some(Box::new(move |_: &crate::FilePick| Some(picked.clone())));
|
||||
let p = item(&mut app, &ctx, "Replace…");
|
||||
@@ -657,7 +664,8 @@ fn a_vectorcraft_document_places_linked_and_edit_original_opens_it() {
|
||||
src.execute("file.new", &json!({"width": 100, "height": 50})).unwrap();
|
||||
src.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 100, "height": 50})).unwrap();
|
||||
let bytes = vectorcraft_format::save_file(&src.active().unwrap().doc);
|
||||
let path = temp_file("badge.vectorcraft", &bytes);
|
||||
let dir = Folder::new("ui-place-document");
|
||||
let path = dir.file("badge.vectorcraft", &bytes);
|
||||
place_picked(&mut app, &path);
|
||||
let d = app.ui.dialog.as_ref().expect("the Place dialog");
|
||||
assert!(d.bool("link") && d.bool("__documents") && !d.bool("__others"), "Link on, for a document");
|
||||
@@ -674,7 +682,7 @@ fn a_vectorcraft_document_places_linked_and_edit_original_opens_it() {
|
||||
assert_eq!(app.session.documents().len(), tabs + 1);
|
||||
assert_eq!(app.session.active().unwrap().path.as_deref(), Some(path.as_str()));
|
||||
// A PNG keeps the image tooltip; a PNG and a document, both.
|
||||
let pic = temp_file("pic.png", &png(10, 10, 72.0));
|
||||
let pic = dir.file("pic.png", &png(10, 10, 72.0));
|
||||
place_picked(&mut app, &pic);
|
||||
let d = app.ui.dialog.as_ref().unwrap();
|
||||
assert!(!d.bool("__documents") && crate::dialogs::place::link_tip(d).contains("image file"));
|
||||
@@ -693,7 +701,8 @@ fn the_place_dialog_links_a_pdf_page_and_embeds_it_with_link_off() {
|
||||
src.execute("file.new", &json!({"width": 100, "height": 50})).unwrap();
|
||||
src.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 100, "height": 50})).unwrap();
|
||||
let pdf = src.execute("document.serialize", &json!({"format": "pdf", "preserveEditing": false})).unwrap();
|
||||
let path = temp_file("flyer.pdf", &vectorcraft_format::base64_decode(pdf["dataBase64"].as_str().unwrap()).unwrap());
|
||||
let dir = Folder::new("ui-place-pdf");
|
||||
let path = dir.file("flyer.pdf", &vectorcraft_format::base64_decode(pdf["dataBase64"].as_str().unwrap()).unwrap());
|
||||
// Link on (the default): one locked object, linked to the file.
|
||||
place_picked(&mut app, &path);
|
||||
let d = app.ui.dialog.as_ref().expect("the Place dialog");
|
||||
@@ -715,7 +724,8 @@ fn the_place_dialog_links_a_pdf_page_and_embeds_it_with_link_off() {
|
||||
fn the_place_dialog_does_not_offer_a_postscript_ai_as_a_locked_object() {
|
||||
let mut app = app();
|
||||
let ps = b"%!PS-Adobe-3.0\n%%BoundingBox: 0 0 100 100\n%%EndComments\n1 0 0 setrgbcolor 10 10 50 50 rectfill\nshowpage\n%%EOF\n";
|
||||
let path = temp_file("legacy.ai", ps);
|
||||
let dir = Folder::new("ui-place-postscript");
|
||||
let path = dir.file("legacy.ai", ps);
|
||||
// file.place embeds a .ai saved without PDF compatibility, even with Link on.
|
||||
let r = app.session.execute("file.place", &json!({"path": path, "link": true})).unwrap();
|
||||
assert_eq!(r["linked"], json!(false), "{r}");
|
||||
@@ -748,7 +758,8 @@ fn holding_escape_with_the_place_cursor_loaded_discards_one_file() {
|
||||
app.run("shortcuts.set", json!({"id": "select.none", "shortcut": "Escape", "force": true})).unwrap();
|
||||
let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap()["id"].clone();
|
||||
app.run("select.set", json!({"ids": [id]})).unwrap();
|
||||
let paths: Vec<String> = ["held-a.png", "held-b.png", "held-c.png"].iter().map(|name| temp_file(name, &png(10, 10, 72.0))).collect();
|
||||
let dir = Folder::new("ui-place-held-escape");
|
||||
let paths: Vec<String> = ["held-a.png", "held-b.png", "held-c.png"].iter().map(|name| dir.file(name, &png(10, 10, 72.0))).collect();
|
||||
app.run("file.place", json!({"paths": paths})).unwrap();
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
assert_eq!(app.session.tool_options()["count"], 3);
|
||||
@@ -774,7 +785,8 @@ fn holding_a_chord_bound_to_a_command_repeats_it_with_the_place_cursor_loaded()
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
app.run("shortcuts.set", json!({"id": "view.zoomIn", "shortcut": "Shift+Escape", "force": true})).unwrap();
|
||||
let paths: Vec<String> = ["chord-a.png", "chord-b.png"].iter().map(|name| temp_file(name, &png(10, 10, 72.0))).collect();
|
||||
let dir = Folder::new("ui-place-held-chord");
|
||||
let paths: Vec<String> = ["chord-a.png", "chord-b.png"].iter().map(|name| dir.file(name, &png(10, 10, 72.0))).collect();
|
||||
app.run("file.place", json!({"paths": paths})).unwrap();
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
let modifiers = egui::Modifiers::SHIFT;
|
||||
@@ -793,7 +805,8 @@ fn holding_a_chord_bound_to_a_command_repeats_it_with_the_place_cursor_loaded()
|
||||
fn crop_image_shows_a_box_that_apply_crops_to() {
|
||||
use vectorcraft_tools::ToolKey;
|
||||
let mut app = app();
|
||||
place_picked(&mut app, &temp_file("crop.png", &png(100, 50, 72.0)));
|
||||
let dir = Folder::new("ui-place-crop");
|
||||
place_picked(&mut app, &dir.file("crop.png", &png(100, 50, 72.0)));
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("link".into(), json!(false));
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
let whole = selected_image(&app).geometric_bounds().unwrap();
|
||||
@@ -899,7 +912,8 @@ fn a_file_placed_while_idle_follows_its_changes() {
|
||||
// Half a second later, before the next look is due, a file is placed. The place itself is a
|
||||
// frame (as any command); then nothing happens for 3 s.
|
||||
time += 0.5;
|
||||
let path = temp_file("idle-watch.png", &png(40, 30, 72.0));
|
||||
let dir = Folder::new("ui-place-idle-watch");
|
||||
let path = dir.file("idle-watch.png", &png(40, 30, 72.0));
|
||||
app.run("file.place", json!({"path": path})).unwrap();
|
||||
let id = app.session.active().unwrap().selection.objects[0];
|
||||
idle(&mut app, &ctx, &mut time, 3.0, &|_| false);
|
||||
@@ -925,7 +939,8 @@ fn a_look_whose_worker_stopped_does_not_stop_later_looks() {
|
||||
// Every frame renders on this thread: a frame finished by the render worker asks for a repaint.
|
||||
app.canvas.worker_started = true;
|
||||
app.run("prefs.set", json!({"key": "updateLinks", "value": "automatically"})).unwrap();
|
||||
let path = temp_file("stopped-watch.png", &png(40, 30, 72.0));
|
||||
let dir = Folder::new("ui-place-stopped-watch");
|
||||
let path = dir.file("stopped-watch.png", &png(40, 30, 72.0));
|
||||
app.run("file.place", json!({"path": path})).unwrap();
|
||||
let id = app.session.active().unwrap().selection.objects[0];
|
||||
let ctx = egui::Context::default();
|
||||
|
||||
@@ -121,12 +121,10 @@ fn an_image_with_vector_art_offers_make_clipping_mask() {
|
||||
image::RgbaImage::from_pixel(20, 20, image::Rgba([0, 128, 255, 255]))
|
||||
.write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png)
|
||||
.unwrap();
|
||||
let dir = std::env::temp_dir().join(format!("vectorcraft-ui-taskbar-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let path = dir.join("blue.png");
|
||||
std::fs::write(&path, &png).unwrap();
|
||||
let dir = crate::tests_folder::Folder::new("ui-taskbar");
|
||||
let path = dir.file("blue.png", &png);
|
||||
app.services.read = Some(Box::new(|p: &str| std::fs::read(p).map_err(|e| e.to_string())));
|
||||
app.run("file.place", json!({"path": path.to_string_lossy(), "link": false})).unwrap();
|
||||
app.run("file.place", json!({"path": path, "link": false})).unwrap();
|
||||
let img = app.session.active().unwrap().selection.objects[0].0;
|
||||
assert!(matches!(kind(&app, img), NodeKind::Image(_)));
|
||||
let shape = id(app.run("shape.ellipse", json!({"x": 150, "y": 100, "width": 60, "height": 60})).unwrap());
|
||||
|
||||
Reference in New Issue
Block a user