78 lines
4.3 KiB
Rust
78 lines
4.3 KiB
Rust
//! VectorCraft's own Fonts folder: a missing font's file, found in a folder, is copied into it
|
||
//! without replacing a file there, and type set in the font redraws in it. One test in its own
|
||
//! process, so the process-wide font database and Fonts folder start fresh, as when the app starts.
|
||
// Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md › Robustness).
|
||
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
||
|
||
use std::time::{Duration, Instant};
|
||
|
||
use serde_json::{Value, json};
|
||
use vectorcraft_engine::Session;
|
||
use vectorcraft_engine::cmd::findfiles::{Rules, plain};
|
||
|
||
/// `text.findFontFiles {}` once the search ended (10 seconds at most).
|
||
fn finished(s: &mut Session) -> Value {
|
||
let until = Instant::now() + Duration::from_secs(10);
|
||
loop {
|
||
let r = s.execute("text.findFontFiles", &json!({})).unwrap();
|
||
if r["state"] != "searching" || Instant::now() > until {
|
||
return r;
|
||
}
|
||
std::thread::sleep(Duration::from_millis(5));
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn a_found_font_is_copied_without_replacing_a_file_and_its_type_redraws() {
|
||
let root = vectorcraft_testkit::temp_dir("font-folder");
|
||
let _ = std::fs::remove_dir_all(&root);
|
||
std::fs::create_dir_all(root.join("Downloads/Deep")).unwrap();
|
||
let root = plain(std::fs::canonicalize(&root).unwrap());
|
||
let fonts = root.join("App Fonts");
|
||
vectorcraft_text::set_app_font_dir(fonts.clone());
|
||
assert!(vectorcraft_text::system_font_dirs().contains(&fonts));
|
||
let file = root.join("Downloads").join("Deep").join("Findme.otf");
|
||
std::fs::write(&file, vectorcraft_testkit::fonts::renamed("Findme Sans 3")).unwrap();
|
||
let serif = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../assets/fonts/SourceSerif4-Regular.ttf");
|
||
std::fs::copy(serif, root.join("other.ttf")).unwrap();
|
||
|
||
let mut s = Session::new();
|
||
s.search_rules = Some(Rules { user_content: vec![root.clone()], ..Rules::default() });
|
||
s.search_threads = Some(2);
|
||
s.execute("file.new", &json!({"width": 300, "height": 200})).unwrap();
|
||
s.execute("text.create", &json!({"x": 10, "y": 40, "text": "Findme", "font": "Findme Sans 3"})).unwrap();
|
||
let r = s.execute("text.missingFonts", &json!({})).unwrap();
|
||
assert_eq!((r["fonts"][0]["family"].as_str(), r["fonts"][0]["status"].as_str()), (Some("Findme Sans 3"), Some("missing")), "{r}");
|
||
s.doc_mut().unwrap().mark_saved();
|
||
let revision = s.doc().unwrap().revision;
|
||
|
||
s.execute("text.findFontFiles", &json!({"folder": root})).unwrap();
|
||
let r = finished(&mut s);
|
||
assert_eq!((&r["state"], &r["fonts"][0]["files"]), (&json!("done"), &json!([file])), "{r}");
|
||
|
||
// A file of that name is in the Fonts folder already: it stays, and the copy takes a number.
|
||
std::fs::create_dir_all(&fonts).unwrap();
|
||
std::fs::write(fonts.join("Findme.otf"), b"keep").unwrap();
|
||
let r = s.execute("text.addFontFiles", &json!({"files": [file]})).unwrap();
|
||
assert_eq!(r["copied"], json!([{"from": file, "to": fonts.join("Findme 2.otf")}]), "{r}");
|
||
assert!(r["faces"].as_u64().is_some_and(|n| n > 0) && r["families"].as_u64().is_some(), "{r}");
|
||
assert_eq!(std::fs::read(fonts.join("Findme.otf")).unwrap(), b"keep");
|
||
|
||
// The type is set in the font now, without editing the document.
|
||
let listed = s.execute("text.fonts", &json!({})).unwrap();
|
||
let findme = listed.as_array().unwrap().iter().find(|f| f["family"] == "Findme Sans 3").cloned().unwrap();
|
||
assert_eq!((findme["status"].as_str(), findme["resolved"]["family"].as_str()), (Some("exact"), Some("Findme Sans 3")), "{findme}");
|
||
let st = s.doc().unwrap();
|
||
assert!(st.revision > revision && !st.is_dirty());
|
||
assert_eq!(s.execute("text.missingFonts", &json!({})).unwrap()["count"], 0);
|
||
|
||
// The same file again is kept, not copied a third time.
|
||
let r = s.execute("text.addFontFiles", &json!({"files": [file]})).unwrap();
|
||
assert_eq!((r["copied"].clone(), r["kept"].clone()), (json!([]), json!([{"from": file, "to": fonts.join("Findme 2.otf")}])), "{r}");
|
||
assert!(!fonts.join("Findme 3.otf").exists());
|
||
// Only files the last search found are copied.
|
||
let r = s.execute("text.addFontFiles", &json!({"files": [root.join("other.ttf")]}));
|
||
assert!(r.as_ref().is_err_and(|e| e.to_string().contains("the last text.findFontFiles search")), "{r:?}");
|
||
let _ = std::fs::remove_dir_all(&root);
|
||
}
|