1use crate::db::{CustomDataItem, IconId, Times, entry::Entry, node::*, rc_refcell_node};
2use std::collections::HashMap;
3use uuid::Uuid;
4
5pub(crate) enum SearchField {
6 Uuid,
7 Title,
8}
9
10impl SearchField {
11 pub(crate) fn matches(&self, node: &NodePtr, field_value: &str) -> bool {
12 match self {
13 SearchField::Uuid => node.borrow().get_uuid().to_string() == field_value,
14 SearchField::Title => match node.borrow().get_title() {
15 Some(title) => title == field_value,
16 None => false,
17 },
18 }
19 }
20}
21
22#[derive(Debug, Clone)]
24#[cfg_attr(feature = "serialization", derive(serde::Serialize))]
25pub struct Group {
26 pub(crate) uuid: Uuid,
28
29 pub(crate) name: Option<String>,
31
32 pub(crate) notes: Option<String>,
34
35 pub(crate) tags: Vec<String>,
37
38 pub(crate) icon_id: Option<IconId>,
40
41 pub(crate) custom_icon_uuid: Option<Uuid>,
43
44 pub(crate) children: Vec<SerializableNodePtr>,
46
47 pub(crate) times: Times,
49
50 pub(crate) custom_data: HashMap<String, CustomDataItem>,
52
53 pub(crate) is_expanded: bool,
55
56 pub(crate) default_autotype_sequence: Option<String>,
58
59 pub(crate) enable_autotype: Option<bool>,
61
62 pub(crate) enable_searching: Option<bool>,
64
65 pub(crate) last_top_visible_entry: Option<Uuid>,
69
70 pub(crate) parent: Option<Uuid>,
71
72 pub(crate) previous_parent_group: Option<Uuid>,
74}
75
76impl Default for Group {
77 fn default() -> Self {
78 Self {
79 uuid: Uuid::new_v4(),
80 name: Some("Default Group".to_string()),
81 notes: None,
82 tags: Vec::new(),
83 icon_id: Some(IconId::FOLDER),
84 custom_icon_uuid: None,
85 children: Vec::new(),
86 times: Times::new(),
87 custom_data: Default::default(),
88 is_expanded: false,
89 default_autotype_sequence: None,
90 enable_autotype: None,
91 enable_searching: None,
92 last_top_visible_entry: None,
93 parent: None,
94 previous_parent_group: None,
95 }
96 }
97}
98
99impl PartialEq for Group {
100 fn eq(&self, other: &Self) -> bool {
101 self.uuid == other.uuid
102 && self.compare_children(other)
103 && self.times == other.times
104 && self.name == other.name
105 && self.notes == other.notes
106 && self.icon_id == other.icon_id
107 && self.custom_icon_uuid == other.custom_icon_uuid
108 && self.is_expanded == other.is_expanded
109 && self.default_autotype_sequence == other.default_autotype_sequence
110 && self.enable_autotype == other.enable_autotype
111 && self.enable_searching == other.enable_searching
112 && self.last_top_visible_entry == other.last_top_visible_entry
113 && self.custom_data == other.custom_data
114 }
116}
117
118impl Eq for Group {}
119
120impl Node for Group {
121 fn duplicate(&self) -> NodePtr {
122 let mut new_group = self.clone();
123 new_group.parent = None;
124 new_group.children = self
125 .children
126 .iter()
127 .map(|child| {
128 let child = child.borrow().duplicate();
129 child.borrow_mut().set_parent(Some(new_group.uuid));
130 child.into()
131 })
132 .collect();
133 rc_refcell_node(new_group)
134 }
135
136 fn get_uuid(&self) -> Uuid {
137 self.uuid
138 }
139
140 fn set_uuid(&mut self, uuid: Uuid) {
141 self.uuid = uuid;
142 }
143
144 fn get_title(&self) -> Option<&str> {
145 self.name.as_deref()
146 }
147
148 fn set_title(&mut self, title: Option<&str>) {
149 self.name = title.map(std::string::ToString::to_string);
150 }
151
152 fn get_notes(&self) -> Option<&str> {
153 self.notes.as_deref()
154 }
155
156 fn set_notes(&mut self, notes: Option<&str>) {
157 self.notes = notes.map(std::string::ToString::to_string);
158 }
159
160 fn get_icon_id(&self) -> Option<IconId> {
161 self.icon_id
162 }
163
164 fn set_icon_id(&mut self, icon_id: Option<IconId>) {
165 self.icon_id = icon_id;
166 }
167
168 fn get_custom_icon_uuid(&self) -> Option<Uuid> {
169 self.custom_icon_uuid
170 }
171
172 fn get_times(&self) -> &Times {
173 &self.times
174 }
175
176 fn get_times_mut(&mut self) -> &mut Times {
177 &mut self.times
178 }
179
180 fn get_parent(&self) -> Option<Uuid> {
181 self.parent
182 }
183
184 fn set_parent(&mut self, parent: Option<Uuid>) {
185 self.parent = parent;
186 }
187}
188
189impl Group {
190 pub fn new(name: &str) -> Group {
191 Group {
192 name: Some(name.to_string()),
193 ..Group::default()
194 }
195 }
196
197 pub fn get_children(&self) -> Vec<NodePtr> {
198 self.children.iter().map(|c| c.into()).collect()
199 }
200
201 fn compare_children(&self, other: &Self) -> bool {
202 if self.children.len() != other.children.len() {
203 return false;
204 }
205 self.children.iter().zip(other.children.iter()).all(|(a, b)| {
206 if let (Some(a), Some(b)) = (a.borrow().downcast_ref::<Group>(), b.borrow().downcast_ref::<Group>()) {
207 a == b
208 } else if let (Some(a), Some(b)) = (a.borrow().downcast_ref::<Entry>(), b.borrow().downcast_ref::<Entry>()) {
209 a == b
210 } else {
211 false
212 }
213 })
214 }
215
216 pub fn set_name(&mut self, name: &str) {
217 self.name = Some(name.to_string());
218 }
219
220 pub fn tags(&self) -> &[String] {
221 &self.tags
222 }
223
224 pub fn get_tags_mut(&mut self) -> &mut Vec<String> {
225 &mut self.tags
226 }
227
228 pub fn custom_data(&self) -> &HashMap<String, CustomDataItem> {
229 &self.custom_data
230 }
231
232 pub fn custom_data_mut(&mut self) -> &mut HashMap<String, CustomDataItem> {
233 &mut self.custom_data
234 }
235
236 pub fn previous_parent_group(&self) -> Option<Uuid> {
237 self.previous_parent_group
238 }
239
240 pub fn add_child(&mut self, child: NodePtr, index: usize) {
241 child.borrow_mut().set_parent(Some(self.get_uuid()));
242 if index < self.children.len() {
243 self.children.insert(index, child.into());
244 } else {
245 self.children.push(child.into());
246 }
247 }
248
249 pub fn get(group: &NodePtr, path: &[&str]) -> Option<NodePtr> {
266 Self::get_internal(group, path, SearchField::Title)
267 }
268
269 pub fn get_by_uuid<T: AsRef<str>>(group: &NodePtr, path: &[T]) -> Option<NodePtr> {
270 Self::get_internal(group, path, SearchField::Uuid)
271 }
272
273 fn get_internal<T: AsRef<str>>(group: &NodePtr, path: &[T], search_field: SearchField) -> Option<NodePtr> {
274 if path.is_empty() {
275 Some(group.clone())
276 } else if path.len() == 1 {
277 group_get_children(group)
278 .unwrap_or_default()
279 .iter()
280 .find_map(|node| match search_field.matches(node, path[0].as_ref()) {
281 true => Some(node.clone()),
282 false => None,
283 })
284 } else {
285 let head = path[0].as_ref();
286 let tail = &path[1..path.len()];
287 let head_group = group_get_children(group).unwrap_or_default().iter().find_map(|node| {
288 if node_is_group(node) && search_field.matches(node, head) {
289 Some(node.clone())
290 } else {
291 None
292 }
293 })?;
294
295 Self::get_internal(&head_group, tail, search_field)
296 }
297 }
298
299 pub fn entries(&self) -> Vec<NodePtr> {
300 let mut response: Vec<NodePtr> = vec![];
301 for node in &self.children {
302 if node_is_entry(node) {
303 response.push(node.into());
304 }
305 }
306 response
307 }
308
309 pub fn groups(&self) -> Vec<NodePtr> {
310 let mut response: Vec<NodePtr> = vec![];
311 for node in &self.children {
312 if node_is_group(node) {
313 response.push(node.into());
314 }
315 }
316 response
317 }
318
319 pub fn reset_children(&mut self, children: Vec<NodePtr>) {
320 let uuid = self.get_uuid();
321 children.iter().for_each(|c| c.borrow_mut().set_parent(Some(uuid)));
322 self.children = children.into_iter().map(|c| c.into()).collect();
323 }
324}
325
326#[allow(unused_imports)]
327#[cfg(test)]
328mod group_tests {
329 use super::{Entry, Group, Node, Times};
330 #[cfg(feature = "merge")]
331 use crate::db::merge::entry_set_field_and_commit;
332 use crate::db::{rc_refcell_node, *};
333 use std::{thread, time};
334
335 #[cfg(feature = "merge")]
336 #[test]
337 fn test_merge_idempotence() {
338 let destination_group = rc_refcell_node(Group::new("group1"));
339 let entry = rc_refcell_node(Entry::default());
340 let _entry_uuid = entry.borrow().get_uuid();
341 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
342 let count = group_get_children(&destination_group).unwrap().len();
343 group_add_child(&destination_group, entry, count).unwrap();
344
345 let source_group = destination_group.borrow().duplicate();
346
347 let sg2: NodePtr = source_group.clone();
348 let merge_result = Group::merge(&destination_group, &sg2).unwrap();
349 assert_eq!(merge_result.warnings.len(), 0);
350 assert_eq!(merge_result.events.len(), 0);
351
352 with_node::<Group, _, _>(&destination_group, |destination_group| {
353 assert_eq!(destination_group.children.len(), 1);
354 with_node::<Group, _, _>(&source_group, |source_group| {
357 assert_eq!(destination_group, source_group);
358 });
359
360 let entry = destination_group.entries()[0].clone();
361 entry_set_field_and_commit(&entry, "Title", "entry1_updated").unwrap();
362 });
363 let merge_result = Group::merge(&destination_group, &sg2).unwrap();
364 assert_eq!(merge_result.warnings.len(), 0);
365 assert_eq!(merge_result.events.len(), 0);
366
367 let destination_group_just_after_merge = destination_group.borrow().duplicate();
368 let merge_result = Group::merge(&destination_group, &sg2).unwrap();
369 assert_eq!(merge_result.warnings.len(), 0);
370 assert_eq!(merge_result.events.len(), 0);
371
372 assert!(node_is_equals_to(&destination_group_just_after_merge, &destination_group));
375 }
376
377 #[cfg(feature = "merge")]
378 #[test]
379 fn test_merge_add_new_entry() {
380 let destination_group = rc_refcell_node(Group::new("group1"));
381 let source_group = rc_refcell_node(Group::new("group1"));
382
383 let entry = rc_refcell_node(Entry::default());
384 let entry_uuid = entry.borrow().get_uuid();
385 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
386 group_add_child(&source_group, entry, 0).unwrap();
387
388 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
389 assert_eq!(merge_result.warnings.len(), 0);
390 assert_eq!(merge_result.events.len(), 1);
391 {
392 assert_eq!(group_get_children(&destination_group).unwrap().len(), 1);
393 let new_entry = search_node_by_uuid_with_specific_type::<Entry>(&destination_group, entry_uuid);
394 assert!(new_entry.is_some());
395 assert_eq!(new_entry.unwrap().borrow().get_title().unwrap(), "entry1");
396 }
397
398 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
400 assert_eq!(merge_result.warnings.len(), 0);
401 assert_eq!(merge_result.events.len(), 0);
402 assert_eq!(group_get_children(&destination_group).unwrap().len(), 1);
403 }
404
405 #[cfg(feature = "merge")]
406 #[test]
407 fn test_merge_add_new_non_root_entry() {
408 let destination_group = rc_refcell_node(Group::new("group1"));
409 let destination_sub_group = rc_refcell_node(Group::new("subgroup1"));
410
411 group_add_child(&destination_group, destination_sub_group, 0).unwrap();
412
413 let source_group = destination_group.borrow().duplicate();
414 let source_sub_group = with_node::<Group, _, _>(&source_group, |g| g.groups()[0].clone()).unwrap();
415
416 let entry: NodePtr = rc_refcell_node(Entry::default());
417 let _entry_uuid = entry.borrow().get_uuid();
418 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
419 let count = group_get_children(&source_sub_group).unwrap().len();
420 group_add_child(&source_sub_group, entry, count).unwrap();
421
422 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
423 assert_eq!(merge_result.warnings.len(), 0);
424 assert_eq!(merge_result.events.len(), 1);
425 let destination_entries = with_node::<Group, _, _>(&destination_group, |g| g.get_all_entries(&[])).unwrap();
426 assert_eq!(destination_entries.len(), 1);
427 let (_created_entry, created_entry_location) = destination_entries.first().unwrap();
428 println!("{created_entry_location:?}");
429 assert_eq!(created_entry_location.len(), 2);
430 }
431
432 #[cfg(feature = "merge")]
433 #[test]
434 fn test_merge_add_new_entry_new_group() {
435 let destination_group = rc_refcell_node(Group::new("group1"));
436 let _destination_sub_group = rc_refcell_node(Group::new("subgroup1"));
437 let source_group = rc_refcell_node(Group::new("group1"));
438 let source_sub_group = rc_refcell_node(Group::new("subgroup1"));
439
440 let entry = rc_refcell_node(Entry::default());
441 let _entry_uuid = entry.borrow().get_uuid();
442 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
443 group_add_child(&source_sub_group, entry, 0).unwrap();
444 group_add_child(&source_group, source_sub_group, 0).unwrap();
445
446 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
447 assert_eq!(merge_result.warnings.len(), 0);
448 assert_eq!(merge_result.events.len(), 1);
449
450 with_node::<Group, _, _>(&destination_group, |destination_group| {
451 let destination_entries = destination_group.get_all_entries(&[]);
452 assert_eq!(destination_entries.len(), 1);
453 let (_, created_entry_location) = destination_entries.first().unwrap();
454 assert_eq!(created_entry_location.len(), 2);
455 });
456 }
457
458 #[cfg(feature = "merge")]
459 #[test]
460 fn test_merge_entry_relocation_existing_group() {
461 let entry = rc_refcell_node(Entry::default());
462 let entry_uuid = entry.borrow().get_uuid();
463 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
464
465 let destination_group = rc_refcell_node(Group::new("group1"));
466 let destination_sub_group1 = rc_refcell_node(Group::new("subgroup1"));
467 let destination_sub_group2 = rc_refcell_node(Group::new("subgroup2"));
468 let destination_sub_group2_uuid = destination_sub_group2.borrow().get_uuid();
469 group_add_child(&destination_sub_group1, entry, 0).unwrap();
470 group_add_child(&destination_group, destination_sub_group1.borrow().duplicate(), 0).unwrap();
471 group_add_child(&destination_group, destination_sub_group2.borrow().duplicate(), 1).unwrap();
472
473 let source_group = destination_group.borrow().duplicate();
474 assert_eq!(
475 with_node::<Group, _, _>(&source_group, |g| g.get_all_entries(&[])).unwrap().len(),
476 1
477 );
478
479 let destination_group_uuid = destination_group.borrow().get_uuid();
480 let destination_sub_group1_uuid = destination_sub_group1.borrow().get_uuid();
481
482 let location = vec![destination_group_uuid, destination_sub_group1_uuid];
483 let removed_entry = Group::remove_entry(&source_group, entry_uuid, &location).unwrap();
484
485 removed_entry.borrow_mut().get_times_mut().set_location_changed(Some(Times::now()));
486 assert!(
487 with_node::<Group, _, _>(&source_group, |g| g.get_all_entries(&[]))
488 .unwrap()
489 .is_empty()
490 );
491 with_node_mut::<Entry, _, _>(&removed_entry, |entry| {
494 entry.update_history();
495 });
496
497 let location = vec![destination_group_uuid, destination_sub_group2_uuid];
498
499 Group::insert_entry(&source_group, removed_entry, &location).unwrap();
500
501 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
502 assert_eq!(merge_result.warnings.len(), 0);
503 assert_eq!(merge_result.events.len(), 1);
504
505 let destination_entries = with_node::<Group, _, _>(&destination_group, |g| g.get_all_entries(&[])).unwrap();
506 assert_eq!(destination_entries.len(), 1);
507 let (_moved_entry, moved_entry_location) = destination_entries.first().unwrap();
508 assert_eq!(moved_entry_location.len(), 2);
509 assert_eq!(moved_entry_location[0], destination_group_uuid);
510 assert_eq!(moved_entry_location[1], destination_sub_group2_uuid);
511 }
512
513 #[cfg(feature = "merge")]
514 #[test]
515 fn test_merge_entry_relocation_new_group() {
516 let entry = rc_refcell_node(Entry::default());
517 let _entry_uuid = entry.borrow().get_uuid();
518 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
519
520 let destination_group = rc_refcell_node(Group::new("group1"));
521 let uuid1 = destination_group.borrow().get_uuid();
522 let destination_sub_group = rc_refcell_node(Group::new("subgroup1"));
523 group_add_child(&destination_sub_group, entry.borrow().duplicate(), 0).unwrap();
524 group_add_child(&destination_group, destination_sub_group, 0).unwrap();
525
526 let source_group = destination_group.borrow().duplicate();
527 let source_sub_group = rc_refcell_node(Group::new("subgroup2"));
528 let uuid2 = source_sub_group.borrow().get_uuid();
529 thread::sleep(time::Duration::from_secs(1));
530 with_node_mut::<Entry, _, _>(&entry, |entry| {
531 entry.times.set_location_changed(Some(Times::now()));
532 entry.update_history();
535 });
536 group_add_child(&source_sub_group, entry, 0).unwrap();
537 with_node_mut::<Group, _, _>(&source_group, |g| {
538 g.reset_children(vec![]);
539 g.add_child(source_sub_group, 0);
540 })
541 .unwrap();
542
543 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
544 assert_eq!(merge_result.warnings.len(), 0);
545 assert_eq!(merge_result.events.len(), 1);
546
547 let destination_entries = with_node::<Group, _, _>(&destination_group, |g| g.get_all_entries(&[])).unwrap();
548 assert_eq!(destination_entries.len(), 1);
549 let (_, created_entry_location) = destination_entries.first().unwrap();
550 assert_eq!(created_entry_location.len(), 2);
551 assert_eq!(created_entry_location[0], uuid1);
552 assert_eq!(created_entry_location[1], uuid2);
553 }
554
555 #[cfg(feature = "merge")]
556 #[test]
557 fn test_update_in_destination_no_conflict() {
558 let destination_group = rc_refcell_node(Group::new("group1"));
559
560 let entry = rc_refcell_node(Entry::default());
561 let _entry_uuid = entry.borrow().get_uuid();
562 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
563
564 group_add_child(&destination_group, entry, 0).unwrap();
565
566 let source_group = destination_group.borrow().duplicate();
567
568 let entry = with_node::<Group, _, _>(&destination_group, |g| g.entries()[0].clone()).unwrap();
569 entry_set_field_and_commit(&entry, "Title", "entry1_updated").unwrap();
570
571 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
572 assert_eq!(merge_result.warnings.len(), 0);
573 assert_eq!(merge_result.events.len(), 0);
574
575 let entry = with_node::<Group, _, _>(&destination_group, |g| g.entries()[0].clone()).unwrap();
576 assert_eq!(entry.borrow().get_title(), Some("entry1_updated"));
577 }
578
579 #[cfg(feature = "merge")]
580 #[test]
581 fn test_update_in_source_no_conflict() {
582 let destination_group = rc_refcell_node(Group::new("group1"));
583
584 let entry = rc_refcell_node(Entry::default());
585 let _entry_uuid = entry.borrow().get_uuid();
586 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
587 group_add_child(&destination_group, entry, 0).unwrap();
588
589 let source_group = destination_group.borrow().duplicate();
590
591 let entry = with_node::<Group, _, _>(&source_group, |g| g.entries()[0].clone()).unwrap();
592 entry_set_field_and_commit(&entry, "Title", "entry1_updated").unwrap();
593
594 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
595 assert_eq!(merge_result.warnings.len(), 0);
596 assert_eq!(merge_result.events.len(), 1);
597
598 let entry = with_node::<Group, _, _>(&destination_group, |g| g.entries()[0].clone()).unwrap();
599 assert_eq!(entry.borrow().get_title(), Some("entry1_updated"));
600 }
601
602 #[cfg(feature = "merge")]
603 #[test]
604 fn test_update_with_conflicts() {
605 let destination_group = rc_refcell_node(Group::new("group1"));
606
607 let entry = rc_refcell_node(Entry::default());
608 let _entry_uuid = entry.borrow().get_uuid();
609 entry_set_field_and_commit(&entry, "Title", "entry1").unwrap();
610 group_add_child(&destination_group, entry, 0).unwrap();
611
612 let source_group = destination_group.borrow().duplicate();
613
614 let entry = with_node::<Group, _, _>(&destination_group, |g| g.entries()[0].clone()).unwrap();
615 entry_set_field_and_commit(&entry, "Title", "entry1_updated_from_destination").unwrap();
616
617 let entry = with_node::<Group, _, _>(&source_group, |g| g.entries()[0].clone()).unwrap();
618 entry_set_field_and_commit(&entry, "Title", "entry1_updated_from_source").unwrap();
619
620 let merge_result = Group::merge(&destination_group, &source_group).unwrap();
621 assert_eq!(merge_result.warnings.len(), 0);
622 assert_eq!(merge_result.events.len(), 1);
623
624 let entry = with_node::<Group, _, _>(&destination_group, |g| g.entries()[0].clone()).unwrap();
625 assert_eq!(entry.borrow().get_title(), Some("entry1_updated_from_source"));
626
627 let merged_history = with_node::<Entry, _, _>(&entry, |e| e.history.clone().unwrap()).unwrap();
628 assert!(merged_history.is_ordered());
629 assert_eq!(merged_history.entries.len(), 3);
630 let merged_entry = &merged_history.entries[1];
631 assert_eq!(merged_entry.get_title(), Some("entry1_updated_from_destination"));
632
633 let destination_group_dup = destination_group.borrow().duplicate();
635 let merge_result = Group::merge(&destination_group, &destination_group_dup).unwrap();
636 assert_eq!(merge_result.warnings.len(), 0);
637 assert_eq!(merge_result.events.len(), 0);
638 }
639
640 #[test]
641 fn get() {
642 let db = Database::new(Default::default());
643
644 let general_group = rc_refcell_node(Group::new("General"));
645 let sample_entry = rc_refcell_node(Entry::default());
646 sample_entry.borrow_mut().set_title(Some("Sample Entry #2"));
647 group_add_child(&general_group, sample_entry, 0).unwrap();
648 group_add_child(&db.root, general_group, 0).unwrap();
649
650 assert!(Group::get(&db.root, &["General", "Sample Entry #2"]).is_some());
651 assert!(Group::get(&db.root, &["General"]).is_some());
652 assert!(Group::get(&db.root, &["Invalid Group"]).is_none());
653 assert!(Group::get(&db.root, &[]).is_some());
654 }
655
656 #[test]
657 fn get_by_uuid() {
658 let db = Database::new(Default::default());
659
660 let general_group = rc_refcell_node(Group::new("General"));
661 let general_group_uuid = general_group.borrow().get_uuid().to_string();
662 let sample_entry = rc_refcell_node(Entry::default());
663 let sample_entry_uuid = sample_entry.borrow().get_uuid().to_string();
664 sample_entry.borrow_mut().set_title(Some("Sample Entry #2"));
665 group_add_child(&general_group, sample_entry, 0).unwrap();
666 group_add_child(&db.root, general_group, 0).unwrap();
667
668 let invalid_uuid = uuid::Uuid::new_v4().to_string();
669
670 let group_path: [&str; 1] = [general_group_uuid.as_ref()];
672 let entry_path: [&str; 2] = [general_group_uuid.as_ref(), sample_entry_uuid.as_ref()];
673 let invalid_path: [&str; 1] = [invalid_uuid.as_ref()];
674 let empty_path: [&str; 0] = [];
675
676 assert!(Group::get_by_uuid(&db.root, &group_path).is_some());
677 assert!(Group::get_by_uuid(&db.root, &entry_path).is_some());
678 assert!(Group::get_by_uuid(&db.root, &invalid_path).is_none());
679 assert!(Group::get_by_uuid(&db.root, &empty_path).is_some());
680
681 let group_path = vec![general_group_uuid.clone()];
683 let entry_path = vec![general_group_uuid.clone(), sample_entry_uuid.clone()];
684 let invalid_path = vec![invalid_uuid.clone()];
685 let empty_path: Vec<String> = vec![];
686
687 assert!(Group::get_by_uuid(&db.root, &group_path).is_some());
688 assert!(Group::get_by_uuid(&db.root, &entry_path).is_some());
689 assert!(Group::get_by_uuid(&db.root, &invalid_path).is_none());
690 assert!(Group::get_by_uuid(&db.root, &empty_path).is_some());
691 }
692}