1use onestore::{RevisionIndex, Store, TocEdit, document::Document};
2
3/// `source` with `edits` applied.
4fn edited(source: &[u8], edits: &[TocEdit]) -> Result<Vec<u8>, onestore::Error> {
5 let mut image = source.to_vec();
6 if let Some(transaction) = onestore::edit_table_of_contents(source, edits)? {
7 transaction.apply(&mut image)?;
8 }
9 Ok(image)
10}
11
12/// The notebook's colour.
13fn color(bytes: &[u8]) -> Option<u32> {
14 let store = Store::parse(bytes).unwrap();
15 let index = RevisionIndex::parse(&store).unwrap();
16 let document = Document::parse(&index).unwrap();
17 let revision = document.active(document.root).unwrap();
18 match &revision.nodes[&revision.roots[&1]].kind {
19 onestore::document::Kind::Toc { color, .. } => *color,
20 _ => panic!(),
21 }
22}
23
24fn entries(bytes: &[u8]) -> Vec<(String, [u8; 16], u32, Option<u32>)> {
25 let store = Store::parse(bytes).unwrap();
26 assert!(store.checksum_mismatches.is_empty());
27 let index = RevisionIndex::parse(&store).unwrap();
28 let document = Document::parse(&index).unwrap();
29 let revision = document.active(document.root).unwrap();
30 let root = &revision.nodes[&revision.roots[&1]];
31 let onestore::document::Kind::Toc { entries, .. } = &root.kind else {
32 panic!()
33 };
34 entries
35 .iter()
36 .map(|id| match &revision.nodes[id].kind {
37 onestore::document::Kind::Toc {
38 filename,
39 identity,
40 order,
41 color,
42 ..
43 } => (
44 filename.clone().unwrap(),
45 identity.unwrap(),
46 order.unwrap(),
47 *color,
48 ),
49 _ => panic!(),
50 })
51 .collect()
52}
53
54#[test]
55fn sections_and_groups_are_added_renamed_ordered_and_removed_and_the_notebook_coloured() {
56 let a = [1; 16];
57 let b = [2; 16];
58 let toc = onestore::create_table_of_contents(
59 "Open Notebook.onetoc2",
60 &[("Alpha.one", a), ("Beta.one", b)],
61 )
62 .unwrap();
63 let c = [3; 16];
64 let group = [4; 16];
65 let written = edited(
66 &toc,
67 &[
68 TocEdit::Add {
69 filename: "Gamma.one".into(),
70 identity: c,
71 group: false,
72 },
73 TocEdit::Add {
74 filename: "Archive".into(),
75 identity: group,
76 group: true,
77 },
78 ],
79 )
80 .unwrap();
81 assert_eq!(
82 entries(&written),
83 [
84 ("Alpha.one".to_owned(), a, 1, Some(0xffff_ffff)),
85 ("Beta.one".to_owned(), b, 2, Some(0xffff_ffff)),
86 ("Gamma.one".to_owned(), c, 3, Some(0xffff_ffff)),
87 ("Archive".to_owned(), group, 4, None),
88 ]
89 );
90 let again = edited(
91 &written,
92 &[
93 TocEdit::Rename {
94 identity: b,
95 filename: "Renamed.one".into(),
96 },
97 TocEdit::Color(0x00d7ff),
98 TocEdit::Order(vec![group, c]),
99 TocEdit::Remove { identity: a },
100 ],
101 )
102 .unwrap();
103 assert_eq!(
104 entries(&again),
105 [
106 ("Archive".to_owned(), group, 1, None),
107 ("Gamma.one".to_owned(), c, 2, Some(0xffff_ffff)),
108 ("Renamed.one".to_owned(), b, 3, Some(0xffff_ffff)),
109 ]
110 );
111 assert_eq!(color(&again), Some(0x00d7ff));
112 assert!(
113 edited(
114 &again,
115 &[TocEdit::Add {
116 filename: "renamed.one".into(),
117 identity: [9; 16],
118 group: false
119 }]
120 )
121 .is_err()
122 );
123 assert!(edited(&again, &[TocEdit::Remove { identity: a }]).is_err());
124}