fix(tools): h5rs diff compares soft links by target, like h5diff
An OBJ that was a soft link was resolved and its target object compared, so two files whose /g/s both point at /z differed when /z did: exit 1, where h5diff (without --follow-symlinks) compares the links' target paths and exits 0. A soft link is now compared as a link wherever it is, OBJ included. --follow-symlinks compares the objects soft links lead to instead, walks into soft-linked groups, resolves relative targets against the link's group, and treats two dangling links as the same; exit codes equal h5diff's on 14 cases. External links are never followed (documented). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -132,6 +132,23 @@ for name, d in (("big1.h5", 0), ("big2.h5", 1)):
|
||||
f["i"] = np.array([2**60 + d, -(2**62) - d], dtype="i8")
|
||||
f["u"] = np.array([2**64 - 1 - d], dtype="u8")
|
||||
|
||||
# Soft links: the same link targets, whose target objects differ.
|
||||
for name, v in (("soft1.h5", 0), ("soft2.h5", 1)):
|
||||
with h5py.File(os.path.join(out, name), "w") as f:
|
||||
f["z"] = np.arange(4) + v
|
||||
f.create_group("g")["s"] = h5py.SoftLink("/z")
|
||||
grp = f.create_group("grp")
|
||||
grp["d"] = np.arange(3) + v
|
||||
f["lnk"] = h5py.SoftLink("/grp")
|
||||
f["dang"] = h5py.SoftLink("/nowhere")
|
||||
# Soft links: different link targets, whose target objects are equal.
|
||||
for name, t in (("target1.h5", "/a"), ("target2.h5", "/b")):
|
||||
with h5py.File(os.path.join(out, name), "w") as f:
|
||||
f["a"] = np.arange(4)
|
||||
f["b"] = np.arange(4)
|
||||
f["s"] = h5py.SoftLink(t)
|
||||
f["rel"] = h5py.SoftLink("a")
|
||||
|
||||
with h5py.File(os.path.join(out, "userblock.h5"), "w", userblock_size=1024) as f:
|
||||
f["d"] = np.arange(10)
|
||||
|
||||
|
||||
@@ -412,6 +412,45 @@ fn diff_tolerances_compare_large_integers_exactly() {
|
||||
);
|
||||
}
|
||||
|
||||
/// A soft link is compared as a link (its target path), as h5diff does,
|
||||
/// unless `--follow-symlinks`, which compares (and walks into) what it
|
||||
/// leads to; two dangling links are then the same.
|
||||
#[test]
|
||||
fn diff_soft_links_like_h5diff() {
|
||||
let Some(f) = generate() else { return };
|
||||
let (s1, s2, t1, t2) = (
|
||||
f.p("soft1.h5"),
|
||||
f.p("soft2.h5"),
|
||||
f.p("target1.h5"),
|
||||
f.p("target2.h5"),
|
||||
);
|
||||
let fl = "--follow-symlinks";
|
||||
let cases: Vec<(Vec<&str>, i32)> = vec![
|
||||
(vec![&s1, &s2, "/g/s"], 0),
|
||||
(vec![&s1, &s2, "/g"], 0),
|
||||
(vec![&s1, &s2, "/lnk"], 0),
|
||||
(vec![&s1, &s2, "/dang"], 0),
|
||||
(vec![&s1, &s2, "/lnk/d"], 1),
|
||||
(vec![&t1, &t2, "/s"], 1),
|
||||
(vec![&t1, &t2, "/s", "/rel"], 1),
|
||||
(vec![fl, &s1, &s2, "/g/s"], 1),
|
||||
(vec![fl, &s1, &s2, "/g"], 1),
|
||||
(vec![fl, &s1, &s2, "/lnk"], 1),
|
||||
(vec![fl, &s1, &s2, "/dang"], 0),
|
||||
(vec![fl, &s1, &s1], 0),
|
||||
(vec![fl, &t1, &t2, "/s"], 0),
|
||||
(vec![fl, &t1, &t2, "/s", "/rel"], 0),
|
||||
];
|
||||
let have_h5diff = tool_available("h5diff");
|
||||
for (args, want) in cases {
|
||||
if have_h5diff {
|
||||
assert_eq!(code(&run("h5diff", &args)), want, "h5diff {args:?}");
|
||||
}
|
||||
let o = h5rs(&[&["diff"], args.as_slice()].concat());
|
||||
assert_eq!(code(&o), want, "h5rs diff {args:?}: {}", stdout(&o));
|
||||
}
|
||||
}
|
||||
|
||||
/// An object hard-linked under two names is compared under both, with
|
||||
/// everything below it, so a file that shares one object between two names
|
||||
/// equals a file that stores two identical copies.
|
||||
|
||||
Reference in New Issue
Block a user