mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-14 03:01:11 +00:00
Merge pull request #2348 from storytold/test/fontdb-race-coverage
Fix concurrent font integration test file race
This commit is contained in:
@@ -2,15 +2,21 @@
|
||||
//! `--no-system-fonts` or `FIGCRAFT_NO_SYSTEM_FONTS=1` opts out.
|
||||
|
||||
use std::process::Command;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
/// The result of one `figcraft-cli run` step (script file `name`); `opt_out` sets the environment
|
||||
/// variable.
|
||||
fn run_one(name: &str, step: Value, args: &[&str], opt_out: bool) -> Value {
|
||||
static NEXT_SCRIPT: AtomicU64 = AtomicU64::new(0);
|
||||
let d = std::env::temp_dir().join(format!("figcraft-cli-fonts-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&d).unwrap();
|
||||
let script = d.join(format!("{name}.json"));
|
||||
// Tests in this binary run concurrently. `sketch_imports_keep_to_no_system_fonts` also calls
|
||||
// `families`, so a shared `families.json` could be truncated while another child reads it;
|
||||
// an empty script is valid and makes the CLI exit successfully without printing result JSON.
|
||||
let sequence = NEXT_SCRIPT.fetch_add(1, Ordering::Relaxed);
|
||||
let script = d.join(format!("{name}-{sequence}.json"));
|
||||
std::fs::write(&script, json!([step]).to_string()).unwrap();
|
||||
let mut cmd = Command::new(env!("CARGO_BIN_EXE_figcraft-cli"));
|
||||
cmd.arg("run").arg(&script).args(args);
|
||||
@@ -20,8 +26,21 @@ fn run_one(name: &str, step: Value, args: &[&str], opt_out: bool) -> Value {
|
||||
cmd.env_remove("FIGCRAFT_NO_SYSTEM_FONTS");
|
||||
}
|
||||
let out = cmd.output().unwrap();
|
||||
assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr));
|
||||
let line: Value = serde_json::from_slice(&out.stdout).unwrap();
|
||||
assert!(
|
||||
out.status.success(),
|
||||
"{name}: CLI status {:?}; stdout={:?}; stderr={}",
|
||||
out.status.code(),
|
||||
String::from_utf8_lossy(&out.stdout),
|
||||
String::from_utf8_lossy(&out.stderr),
|
||||
);
|
||||
let line: Value = serde_json::from_slice(&out.stdout).unwrap_or_else(|error| {
|
||||
panic!(
|
||||
"{name} {:?}: CLI returned success without JSON: {error}; stdout={:?}; stderr={}",
|
||||
args,
|
||||
String::from_utf8_lossy(&out.stdout),
|
||||
String::from_utf8_lossy(&out.stderr),
|
||||
)
|
||||
});
|
||||
line["result"].clone()
|
||||
}
|
||||
|
||||
|
||||
@@ -376,9 +376,19 @@ fn font_bytes_load_into_the_db() {
|
||||
let families = load_font_bytes(f.bytes.to_vec());
|
||||
assert_eq!(families.len(), 1);
|
||||
assert!(families.iter().all(|f| has_family(f)));
|
||||
let faces = db().read().unwrap().face_count();
|
||||
// The global face count can grow here when another test finishes the concurrent system
|
||||
// font scan. Count explicitly loaded faces from this family so the idempotency assertion
|
||||
// stays isolated from unrelated installed fonts.
|
||||
let loaded_faces = || {
|
||||
let db = db().read().unwrap();
|
||||
families
|
||||
.iter()
|
||||
.map(|family| db.faces.iter().filter(|face| face.loaded > 0 && face.family.eq_ignore_ascii_case(family)).count())
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let faces = loaded_faces();
|
||||
assert_eq!(load_font_bytes(f.bytes.to_vec()), families);
|
||||
assert_eq!(db().read().unwrap().face_count(), faces);
|
||||
assert_eq!(loaded_faces(), faces);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user