Merge pull request #3647 from dotCooCoo/fix/package-names-a-rejected-path-once

Package: a file the writer refuses is named once in the error
This commit is contained in:
BFlat
2026-10-22 23:54:23 +07:00
committed by GitHub
2 changed files with 31 additions and 1 deletions
+3 -1
View File
@@ -129,7 +129,9 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
let later = Rc::new(Cell::new(false));
let in_background = later.clone();
let work = move |write: Writer| {
let mut write = |path: &str, bytes: &[u8]| write(path, bytes).map_err(|e| EngineError::Other(format!("{path}: {e}")));
// A writer error that already names the file (an automation root's refusal) is kept as it is.
let mut write =
|path: &str, bytes: &[u8]| write(path, bytes).map_err(|e| EngineError::Other(if e.contains(path) { e } else { format!("{path}: {e}") }));
package.write(&mut write).map_err(|e| e.to_string())
};
let r = background::run(app, enabled, label, None, work, move |app, r| packaged(app, r, web, in_background.get()))?;
@@ -6,6 +6,7 @@ use std::sync::Arc;
use serde_json::json;
use vectorcraft_engine::Session;
use vectorcraft_engine::file_access::{Access, AutomationRoots};
use super::*;
use crate::background;
@@ -298,6 +299,33 @@ fn package_status_without_notes_has_no_extra_spaces() {
assert!(!detail.contains(" ."), "{detail}");
}
/// A file the writer refuses is named once in the status bar: a refusal from the automation-root
/// check already names the path, and an error without it gets the path in front.
#[test]
fn a_refused_file_is_named_once() {
let dir = Folder::new("refused");
let mut app = saved(&dir);
app.session.execute("prefs.set", &json!({"values": {"backgroundExport": false}})).unwrap();
let (out, elsewhere, other) = (dir.path("out"), dir.path("elsewhere"), dir.path("other"));
std::fs::create_dir_all(&elsewhere).unwrap();
std::fs::create_dir_all(&other).unwrap();
let doc = std::path::Path::new(&out).join("card Folder").join("card.vectorcraft").to_string_lossy().into_owned();
let (elsewhere, other) = (std::path::Path::new(&elsewhere), std::path::Path::new(&other));
for write_roots in [vec![elsewhere], vec![elsewhere, other]] {
let roots = AutomationRoots::new(&[], &write_roots).unwrap().unwrap();
let refused = roots.check(&doc, Access::Write).unwrap_err();
assert!(refused.ends_with(&doc), "{refused}");
app.services.write = Some(Box::new(move |p: &str, _: &[u8]| roots.check(p, Access::Write)));
package_dialog(&mut app, &out);
assert_eq!(confirm(&mut app), Err(refused.clone()));
assert_eq!(app.ui.status, refused);
}
app.services.write = Some(Box::new(|_: &str, _: &[u8]| Err("Access is denied. (os error 5)".into())));
package_dialog(&mut app, &out);
assert!(confirm(&mut app).is_err());
assert_eq!(app.ui.status, format!("{doc}: Access is denied. (os error 5)"));
}
#[test]
fn package_without_a_location_says_so() {
let dir = Folder::new("empty");