1use onestore::{IdStream, PropertySets, Reference, Store, Value};
2use std::fs;
3
4#[test]
5fn native_property_chunks_preserve_unicode_and_ascii_text() {
6 let bytes =
7 fs::read("../../corpus/native/20260905-05/snapshots/07-table/notebook/synthetic.one")
8 .unwrap();
9 let store = Store::parse(&bytes).unwrap();
10 let mut strings = Vec::new();
11 for node in store.lists.values().flat_map(|list| &list.nodes) {
12 if matches!(node.id, 0xa4 | 0xa5 | 0xc4 | 0xc5)
13 && let Some(Reference::Data(chunk)) = node.reference
14 {
15 let start = usize::try_from(chunk.offset).unwrap();
16 let end = start + usize::try_from(chunk.length).unwrap();
17 let object = PropertySets::parse(&bytes[start..end]).unwrap();
18 for property in object.sets.iter().flatten() {
19 if let Value::Bytes(data) = property.value {
20 if property.id == 0x1c001c22 {
21 let text = String::from_utf16(
22 &data
23 .chunks_exact(2)
24 .map(|pair| u16::from_le_bytes([pair[0], pair[1]]))
25 .collect::<Vec<_>>(),
26 )
27 .unwrap();
28 assert!(text.ends_with('\0'));
29 strings.push(text.trim_end_matches('\0').to_owned());
30 } else if property.id == 0x1c003498 && data.is_ascii() {
31 strings.push(String::from_utf8(data.to_vec()).unwrap());
32 }
33 }
34 }
35 }
36 }
37 for expected in [
38 "Fictitious: café, 東京, مرحبا",
39 "Fictitious positioned outline.",
40 "Left cell",
41 "Right cell",
42 ] {
43 assert!(
44 strings.iter().any(|text| text == expected),
45 "{expected}: {strings:?}"
46 );
47 }
48}
49
50#[test]
51fn property_nesting_does_not_use_the_call_stack() {
52 let mut bytes = 0x80000000_u32.to_le_bytes().to_vec();
53 for _ in 0..100_000 {
54 bytes.extend_from_slice(&1_u16.to_le_bytes());
55 bytes.extend_from_slice(&0x44000001_u32.to_le_bytes());
56 }
57 bytes.extend_from_slice(&0_u16.to_le_bytes());
58 let properties = PropertySets::parse(&bytes).unwrap();
59 assert_eq!(properties.sets.len(), 100_001);
60 drop(properties);
61}
62
63#[test]
64fn nested_sets_consume_reference_streams_in_property_order() {
65 let mut bytes = 0x80000002_u32.to_le_bytes().to_vec();
66 bytes.extend_from_slice(&0x101_u32.to_le_bytes());
67 bytes.extend_from_slice(&0x202_u32.to_le_bytes());
68 bytes.extend_from_slice(&2_u16.to_le_bytes());
69 bytes.extend_from_slice(&0x44000001_u32.to_le_bytes());
70 bytes.extend_from_slice(&0x20000002_u32.to_le_bytes());
71 bytes.extend_from_slice(&1_u16.to_le_bytes());
72 bytes.extend_from_slice(&0x20000003_u32.to_le_bytes());
73 let properties = PropertySets::parse(&bytes).unwrap();
74 assert_eq!(properties.sets[0][0].value, Value::Sets(1..2));
75 assert_eq!(
76 properties.sets[1][0].value,
77 Value::References {
78 stream: IdStream::Objects,
79 compact_ids: &0x101_u32.to_le_bytes()
80 }
81 );
82 assert_eq!(
83 properties.sets[0][1].value,
84 Value::References {
85 stream: IdStream::Objects,
86 compact_ids: &0x202_u32.to_le_bytes()
87 }
88 );
89}
90
91#[test]
92fn impossible_nested_array_sizes_are_rejected_before_allocation() {
93 let mut bytes = 0x80000000_u32.to_le_bytes().to_vec();
94 bytes.extend_from_slice(&1_u16.to_le_bytes());
95 bytes.extend_from_slice(&0x40000001_u32.to_le_bytes());
96 bytes.extend_from_slice(&u32::MAX.to_le_bytes());
97 bytes.extend_from_slice(&0x44000000_u32.to_le_bytes());
98 assert!(PropertySets::parse(&bytes).is_err());
99}