hayro-syntax: tests check that valid entries survive an unreadable value, and Debug prints the closing brace

Dict's and Array's Debug impls built their output with debug_struct and
debug_list but returned Ok(()) instead of calling finish(), so the
closing brace or bracket was never written: a dictionary printed as
Dict { "B": Boolean(true). Both now end with finish(), as upstream
hayro's do.

The tests from #165 only checked that nothing panics. They now parse a
dictionary with a valid entry on each side of an unreadable value (/#zz,
12-.5, and a dictionary followed by stream with no endstream) and check
that both valid entries come back with their values. The array test
checks that the items before an unreadable item (/#zz, 12-.5) come back
with their values. Both tests also check the Debug output.

Update the local hashes of dict.rs and array.rs and the repair list in
SOURCE.json, and note the change in vendor/README.craft-reader.md.
This commit is contained in:
dotCooCoo committed 2026-10-31 21:03:34 -07:00
1 parent f8f8829cc7
commit c04f773850
4 files changed
+52 -10

No files matched your search

+1
View File
@@ -113,6 +113,7 @@ Raw array iteration now ends safely if validation and object parsing disagree;
standalone sign tokens retain the reader's zero tolerance.
`Dict::entries` and a dictionary's `Debug` output skip an entry whose value does not parse,
as in [Hayro #1501](https://github.com/LaurenzV/hayro/pull/1501).
The `Debug` output of a dictionary or an array ends with its closing brace or bracket.
Byte transfer-function samples use rounded 8-bit values; failed or non-finite evaluations
leave the sample unchanged. Historical source hashes remain in each `SOURCE.json`,
alongside local hashes and the compatibility reference.
+4 -3
View File
@@ -212,7 +212,7 @@
"path": "src/object/array.rs",
"source_sha256": "6fbddf05724848db2389068a0504cff6b0783e35baa58e64bf2a31d48a1042ea",
"source_git_blob": "d39230f7dbf114dd202a16b21f7a6bb70be5ead3",
"sha256": "4537ab5cc06383e8b1e0dc97ae9fa1ee2869201615a37dea26bd0665006b2dd0"
"sha256": "8d5704b638f5198ec74604a3fd88a32dee553b6dc2a7010e746ef5e459759ed6"
},
{
"path": "src/object/bool.rs",
@@ -230,7 +230,7 @@
"path": "src/object/dict.rs",
"source_sha256": "bcfefabe931614b79ea54940d02fce534eb2363f1b75a03d6428fd7a04c57981",
"source_git_blob": "1e016b567e8ec17801fa8282c47f653092839cb5",
"sha256": "dac4329027aacb68c937fb2aa4b839960e0a94b6af40c4176b614ffa48157933"
"sha256": "b5699e0774bbb4dfd1ad8c6fa713274c854f10d8afcc8cbe5544bdda79b59bde"
},
{
"path": "src/object/indirect.rs",
@@ -371,6 +371,7 @@
"local_safety_repairs": [
"Match existing standalone-plus-as-zero tolerance in number parsing while retaining regular-character terminator rejection and numeric overflow guards.",
"End raw array iteration on object parse failure instead of panicking when validation and parsing differ.",
"Skip a dictionary entry whose value does not parse in Dict::entries and Dict's Debug output instead of panicking, as in LaurenzV/hayro#1501 (23a8e290d4195ab31f737c12a1b079c114cdd13c)."
"Skip a dictionary entry whose value does not parse in Dict::entries and Dict's Debug output instead of panicking, as in LaurenzV/hayro#1501 (23a8e290d4195ab31f737c12a1b079c114cdd13c).",
"End Dict and Array Debug output with finish(), as upstream does, so the closing brace or bracket is printed."
]
}
+21 -2
View File
@@ -62,7 +62,7 @@ impl Debug for Array<'_> {
debug_list.entry(&i);
});
Ok(())
debug_list.finish()
}
}
@@ -443,6 +443,25 @@ mod tests {
#[test]
fn array_with_unreadable_item() {
let _ = array_ref_impl(b"[true /#zz false]");
for bytes in [
b"[true false /#zz true]".as_slice(),
b"[true false 12-.5 true]",
] {
let values = array_ref_impl(bytes).unwrap();
assert_eq!(values.len(), 2);
assert!(matches!(values[0], MaybeRef::NotRef(Object::Boolean(true))));
assert!(matches!(
values[1],
MaybeRef::NotRef(Object::Boolean(false))
));
let array = Reader::new(bytes)
.read_with_context::<Array<'_>>(&ReaderContext::new(XRef::dummy(), false))
.unwrap();
assert_eq!(
alloc::format!("{array:?}"),
"[Boolean(true), Boolean(false)]"
);
}
}
}
+26 -5
View File
@@ -160,7 +160,7 @@ impl Debug for Dict<'_> {
for (key, value) in self.entries() {
debug_struct.field(&format!("{:?}", key.as_str()), &value);
}
Ok(())
debug_struct.finish()
}
}
@@ -1258,7 +1258,7 @@ mod tests {
use crate::object::dict::keys::{COLORSPACE, EXT_G_STATE, FONT, PROC_SET};
use crate::object::dict::{Dict, InlineImageDict};
use crate::object::string;
use crate::object::{FromBytes, Name, ObjRef};
use crate::object::{FromBytes, MaybeRef, Name, ObjRef, Object};
use crate::reader::Reader;
use crate::reader::{ReaderContext, ReaderExt};
@@ -1404,8 +1404,29 @@ mod tests {
#[test]
fn dict_with_unreadable_value() {
let dict = Dict::from_bytes(b"<< /A /#zz /B true >>").unwrap();
let _ = dict.entries().count();
let _ = alloc::format!("{dict:?}");
for bytes in [
b"<< /A false /B /#zz /C true >>".as_slice(),
b"<< /A false /B 12-.5 /C true >>",
b"<< /A false /B << /Length 3 >> stream /C true >>",
] {
let dict = Dict::from_bytes(bytes).unwrap();
assert_eq!(dict.keys().count(), 3);
let entries = dict.entries().collect::<Vec<_>>();
assert_eq!(entries.len(), 2);
assert_eq!(entries[0].0.as_str(), "A");
assert!(matches!(
entries[0].1,
MaybeRef::NotRef(Object::Boolean(false))
));
assert_eq!(entries[1].0.as_str(), "C");
assert!(matches!(
entries[1].1,
MaybeRef::NotRef(Object::Boolean(true))
));
assert_eq!(
alloc::format!("{dict:?}"),
"Dict { \"A\": Boolean(false), \"C\": Boolean(true) }"
);
}
}
}