#3538: test that OCIO transform files and configs are read again once they change

This commit is contained in:
arnav-hiwarkar committed 2026-11-12 14:33:21 +05:30
1 parent 41585f2aec
commit 0547c51e47
2 files changed
+82

No files matched your search

+40
View File
@@ -396,3 +396,43 @@ fn color_stabilizer_samples_the_reference_at_the_points_reference_positions() {
assert!((o(x) - (a + b * v(x))).abs() < 1e-3, "x {x}");
}
}
/// Writes `text` to `dir/name` with modification time `secs` (so an edit within the file system's
/// time resolution still moves the stamp), returning the path.
fn write_dated(dir: &std::path::Path, name: &str, text: &str, secs: u64) -> String {
let path = dir.join(name);
std::fs::write(&path, text).unwrap();
let f = std::fs::File::options().write(true).open(&path).unwrap();
f.set_modified(std::time::UNIX_EPOCH + std::time::Duration::from_secs(secs)).unwrap();
path.to_string_lossy().into_owned()
}
/// #3538: OCIO File Transform read a file once per process; an edited, created, repaired or
/// deleted file was never followed.
#[test]
fn an_ocio_transform_file_is_read_again_once_it_changes() {
const BLACK: &str = "LUT_1D_SIZE 2\n0 0 0\n0 0 0\n";
const WHITE: &str = "LUT_1D_SIZE 2\n1 1 1\n1 1 1\n";
let dir = std::env::temp_dir().join(format!("ec-fx-3538-file-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let at = |src: &str| load_file(src).map(|x| x.apply([0.5; 3], 1, false, ""));
let edited = write_dated(dir.as_path(), "edited.cube", BLACK, 1_000);
assert_eq!(at(&edited), Some([0.0; 3]));
write_dated(dir.as_path(), "edited.cube", WHITE, 2_000);
assert_eq!(at(&edited), Some([1.0; 3]), "an edited file, same size");
let created = dir.as_path().join("created.cube").to_string_lossy().into_owned();
assert_eq!(at(&created), None);
write_dated(dir.as_path(), "created.cube", WHITE, 1_000);
assert_eq!(at(&created), Some([1.0; 3]), "a file created after a failed load");
let repaired = write_dated(dir.as_path(), "repaired.cube", "not a lut", 1_000);
assert_eq!(at(&repaired), None);
write_dated(dir.as_path(), "repaired.cube", WHITE, 2_000);
assert_eq!(at(&repaired), Some([1.0; 3]), "a repaired file");
std::fs::remove_file(&repaired).unwrap();
assert_eq!(at(&repaired), None, "a deleted file");
// Inline text is its own content: the same text is the same transform.
let inline = load_file(BLACK).unwrap();
assert!(Arc::ptr_eq(&inline, &load_file(BLACK).unwrap()));
std::fs::remove_dir_all(&dir).unwrap();
}
+42
View File
@@ -410,3 +410,45 @@ fn builtin_styles() {
fn rgb_white_xyz() -> [f64; 3] {
[D65[0] / D65[1], 1.0, (1.0 - D65[0] - D65[1]) / D65[1]]
}
/// #3538: a custom `.ocio` config, and the LUTs it reads, were read once per process.
#[test]
fn an_ocio_config_and_its_luts_are_read_again_once_they_change() {
const BLACK: &str = "LUT_1D_SIZE 2\n0 0 0\n0 0 0\n";
const WHITE: &str = "LUT_1D_SIZE 2\n1 1 1\n1 1 1\n";
let dir = std::env::temp_dir().join(format!("ec-fx-3538-config-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
std::fs::create_dir_all(dir.as_path().join("luts")).unwrap();
let write = |name: &str, text: &str, secs: u64| {
let path = dir.as_path().join(name);
std::fs::write(&path, text).unwrap();
let f = std::fs::File::options().write(true).open(&path).unwrap();
f.set_modified(std::time::UNIX_EPOCH + std::time::Duration::from_secs(secs)).unwrap();
path.to_string_lossy().into_owned()
};
let config = |space: &str| {
format!(
"ocio_profile_version: 2\nsearch_path: luts\nroles:\n scene_linear: lin\ncolorspaces:\n - !<ColorSpace>\n name: lin\n - !<ColorSpace>\n name: {space}\n to_reference: !<FileTransform> {{src: grade.cube, interpolation: linear}}\n - !<ColorSpace>\n name: later\n to_reference: !<FileTransform> {{src: later.cube, interpolation: linear}}\n"
)
};
let src = dir.as_path().join("config.ocio").to_string_lossy().into_owned();
assert!(load_config(&src).is_err(), "no config yet");
write("config.ocio", &config("graded"), 1_000);
write("luts/grade.cube", BLACK, 1_000);
let to_lin = |space: &str| {
let c = load_config(&src).unwrap();
c.convert(c.space(space).unwrap(), c.space("lin").unwrap(), [0.5; 3])
};
assert_eq!(to_lin("graded"), [0.0; 3], "a config created after a failed load");
write("luts/grade.cube", WHITE, 2_000);
assert_eq!(to_lin("graded"), [1.0; 3], "a LUT the config reads, edited");
assert_eq!(to_lin("later"), [0.5; 3], "a LUT not there yet passes through");
write("luts/later.cube", BLACK, 1_000);
assert_eq!(to_lin("later"), [0.0; 3], "a LUT the config reads, created");
write("config.ocio", &config("regraded"), 2_000);
assert!(load_config(&src).unwrap().space("regraded").is_some(), "an edited config");
std::fs::remove_file(&src).unwrap();
assert!(load_config(&src).is_err(), "a deleted config");
std::fs::remove_dir_all(&dir).unwrap();
}