easypdf_core/model/
list_item.rs1#[derive(Clone, Debug, PartialEq)]
16pub struct ListItem {
17 text: String,
19 level: u8,
21 children: Vec<ListItem>,
23}
24
25impl ListItem {
26 #[must_use]
37 pub fn new(text: impl Into<String>) -> Self {
38 Self {
39 text: text.into(),
40 level: 0,
41 children: Vec::new(),
42 }
43 }
44
45 #[must_use]
56 pub const fn with_level(mut self, level: u8) -> Self {
57 self.level = level;
58 self
59 }
60
61 #[must_use]
72 pub fn with_child(mut self, child: ListItem) -> Self {
73 self.children.push(child);
74 self
75 }
76
77 #[must_use]
79 pub fn text(&self) -> &str {
80 &self.text
81 }
82
83 #[must_use]
85 pub const fn level(&self) -> u8 {
86 self.level
87 }
88
89 #[must_use]
91 pub fn children(&self) -> &[ListItem] {
92 &self.children
93 }
94
95 pub fn children_mut(&mut self) -> &mut Vec<ListItem> {
97 &mut self.children
98 }
99}
100
101#[cfg(test)]
102#[allow(clippy::uninlined_format_args, clippy::float_cmp)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn new_creates_default_item() {
108 let item = ListItem::new("Hello");
109 assert_eq!(item.text(), "Hello");
110 assert_eq!(item.level(), 0);
111 assert!(item.children().is_empty());
112 }
113
114 #[test]
115 fn new_accepts_string() {
116 let item = ListItem::new(String::from("Owned"));
117 assert_eq!(item.text(), "Owned");
118 }
119
120 #[test]
121 fn with_level_sets_level() {
122 let item = ListItem::new("Nested").with_level(3);
123 assert_eq!(item.level(), 3);
124 }
125
126 #[test]
127 fn with_level_zero_is_default() {
128 let item = ListItem::new("Top").with_level(0);
129 assert_eq!(item.level(), 0);
130 }
131
132 #[test]
133 fn with_child_adds_child() {
134 let item = ListItem::new("Parent").with_child(ListItem::new("Child"));
135 assert_eq!(item.children().len(), 1);
136 assert_eq!(item.children()[0].text(), "Child");
137 }
138
139 #[test]
140 fn with_child_multiple_children() {
141 let item = ListItem::new("Parent")
142 .with_child(ListItem::new("A"))
143 .with_child(ListItem::new("B"))
144 .with_child(ListItem::new("C"));
145 assert_eq!(item.children().len(), 3);
146 assert_eq!(item.children()[0].text(), "A");
147 assert_eq!(item.children()[1].text(), "B");
148 assert_eq!(item.children()[2].text(), "C");
149 }
150
151 #[test]
152 fn nested_children() {
153 let item = ListItem::new("L0").with_level(0).with_child(
154 ListItem::new("L1")
155 .with_level(1)
156 .with_child(ListItem::new("L2").with_level(2)),
157 );
158 assert_eq!(item.children().len(), 1);
159 assert_eq!(item.children()[0].children().len(), 1);
160 assert_eq!(item.children()[0].children()[0].text(), "L2");
161 }
162
163 #[test]
164 fn children_mut_returns_mutable_ref() {
165 let mut item = ListItem::new("Parent");
166 item.children_mut().push(ListItem::new("MutChild"));
167 assert_eq!(item.children().len(), 1);
168 assert_eq!(item.children()[0].text(), "MutChild");
169 }
170
171 #[test]
172 fn clone_preserves_structure() {
173 let item = ListItem::new("Original")
174 .with_level(1)
175 .with_child(ListItem::new("Child"));
176 let cloned = item.clone();
177 assert_eq!(item, cloned);
178 }
179
180 #[test]
181 fn partial_eq_works() {
182 let a = ListItem::new("Same").with_level(1);
183 let b = ListItem::new("Same").with_level(1);
184 let c = ListItem::new("Different").with_level(1);
185 assert_eq!(a, b);
186 assert_ne!(a, c);
187 }
188
189 #[test]
190 fn debug_includes_fields() {
191 let item = ListItem::new("Debug").with_level(2);
192 let dbg = format!("{:?}", item);
193 assert!(dbg.contains("Debug"));
194 assert!(dbg.contains('2'));
195 }
196}