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 .as_chunks::<2>()
24 .0
25 .iter()
26 .map(|pair| u16::from_le_bytes([pair[0], pair[1]]))
27 .collect::<Vec<_>>(),
28 )
29 .unwrap();
30 assert!(text.ends_with('\0'));
31 strings.push(text.trim_end_matches('\0').to_owned());
32 } else if property.id == 0x1c003498 && data.is_ascii() {
33 strings.push(String::from_utf8(data.to_vec()).unwrap());
34 }
35 }
36 }
37 }
38 }
39 for expected in [
40 "Fictitious: café, 東京, مرحبا",
41 "Fictitious positioned outline.",
42 "Left cell",
43 "Right cell",
44 ] {
45 assert!(
46 strings.iter().any(|text| text == expected),
47 "{expected}: {strings:?}"
48 );
49 }
50}
51
52#[test]
53fn property_nesting_does_not_use_the_call_stack() {
54 let mut bytes = 0x80000000_u32.to_le_bytes().to_vec();
55 for _ in 0..100_000 {
56 bytes.extend_from_slice(&1_u16.to_le_bytes());
57 bytes.extend_from_slice(&0x44000001_u32.to_le_bytes());
58 }
59 bytes.extend_from_slice(&0_u16.to_le_bytes());
60 let properties = PropertySets::parse(&bytes).unwrap();
61 assert_eq!(properties.sets.len(), 100_001);
62 drop(properties);
63}
64
65#[test]
66fn nested_sets_consume_reference_streams_in_property_order() {
67 let mut bytes = 0x80000002_u32.to_le_bytes().to_vec();
68 bytes.extend_from_slice(&0x101_u32.to_le_bytes());
69 bytes.extend_from_slice(&0x202_u32.to_le_bytes());
70 bytes.extend_from_slice(&2_u16.to_le_bytes());
71 bytes.extend_from_slice(&0x44000001_u32.to_le_bytes());
72 bytes.extend_from_slice(&0x20000002_u32.to_le_bytes());
73 bytes.extend_from_slice(&1_u16.to_le_bytes());
74 bytes.extend_from_slice(&0x20000003_u32.to_le_bytes());
75 let properties = PropertySets::parse(&bytes).unwrap();
76 assert_eq!(properties.sets[0][0].value, Value::Sets(1..2));
77 assert_eq!(
78 properties.sets[1][0].value,
79 Value::References {
80 stream: IdStream::Objects,
81 compact_ids: &0x101_u32.to_le_bytes()
82 }
83 );
84 assert_eq!(
85 properties.sets[0][1].value,
86 Value::References {
87 stream: IdStream::Objects,
88 compact_ids: &0x202_u32.to_le_bytes()
89 }
90 );
91}
92
93#[test]
94fn impossible_nested_array_sizes_are_rejected_before_allocation() {
95 let mut bytes = 0x80000000_u32.to_le_bytes().to_vec();
96 bytes.extend_from_slice(&1_u16.to_le_bytes());
97 bytes.extend_from_slice(&0x40000001_u32.to_le_bytes());
98 bytes.extend_from_slice(&u32::MAX.to_le_bytes());
99 bytes.extend_from_slice(&0x44000000_u32.to_le_bytes());
100 assert!(PropertySets::parse(&bytes).is_err());
101}