TF-37 Generate tree with Map
This commit is contained in:
committed by
Dat H. Pham
parent
41b4e8296c
commit
e63298bc29
@@ -1,4 +1,3 @@
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
@@ -8,39 +7,19 @@ class MailboxNode with EquatableMixin{
|
||||
static PresentationMailbox _root = PresentationMailbox(MailboxId(Id('root')));
|
||||
|
||||
PresentationMailbox item;
|
||||
late BuiltList<MailboxNode> childrenItems;
|
||||
List<MailboxNode>? childrenItems;
|
||||
|
||||
factory MailboxNode.root() => MailboxNode(_root);
|
||||
|
||||
bool hasChildren() => childrenItems.isNotEmpty;
|
||||
bool hasChildren() => childrenItems?.isNotEmpty ?? false;
|
||||
|
||||
MailboxNode(this.item, {List<MailboxNode> child = const []}) {
|
||||
this.childrenItems = BuiltList(child);
|
||||
}
|
||||
MailboxNode(this.item, {this.childrenItems});
|
||||
|
||||
MailboxNode? addChild(PresentationMailbox mailbox) {
|
||||
if (_validateChild(mailbox)) {
|
||||
final node = MailboxNode(mailbox);
|
||||
_addChildNode(node);
|
||||
return node;
|
||||
void addChildNode(MailboxNode node) {
|
||||
if (childrenItems == null) {
|
||||
childrenItems = [];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _addChildNode(MailboxNode node) {
|
||||
childrenItems = (ListBuilder<MailboxNode>(childrenItems)
|
||||
..add(node))
|
||||
.build();
|
||||
}
|
||||
|
||||
bool _validateChild(PresentationMailbox mailbox) {
|
||||
if (mailbox.parentId == item.id) {
|
||||
return true;
|
||||
}
|
||||
if (item == _root) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
childrenItems?.add(node);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
|
||||
import 'mailbox_node.dart';
|
||||
|
||||
@@ -10,34 +7,6 @@ class MailboxTree with EquatableMixin {
|
||||
MailboxNode root;
|
||||
MailboxTree(this.root);
|
||||
|
||||
MailboxNode? findNode(MailboxId? mailboxId) {
|
||||
var result;
|
||||
final queue = ListQueue<MailboxNode>();
|
||||
queue.addLast(root);
|
||||
while (queue.isNotEmpty && mailboxId != null) {
|
||||
final currentNode = queue.removeFirst();
|
||||
if (mailboxId == currentNode.item.id) {
|
||||
result = currentNode;
|
||||
break;
|
||||
}
|
||||
currentNode.childrenItems.forEach((child) {
|
||||
queue.addLast(child);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MailboxNode? insertNode(PresentationMailbox mailbox) {
|
||||
if (mailbox.parentId == null) {
|
||||
return root.addChild(mailbox);
|
||||
}
|
||||
|
||||
final foundParent = findNode(mailbox.parentId);
|
||||
return foundParent != null
|
||||
? foundParent.addChild(mailbox)
|
||||
: root.addChild(mailbox);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [root];
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:built_collection/built_collection.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
|
||||
@@ -9,50 +8,24 @@ import 'mailbox_tree.dart';
|
||||
|
||||
class TreeBuilder {
|
||||
Future<MailboxTree> generateMailboxTree(List<PresentationMailbox> mailboxesList) async {
|
||||
final Map<MailboxId, BuiltList<PresentationMailbox>> mapNotFoundParentMailbox = HashMap();
|
||||
final Map<MailboxId, MailboxNode> mailboxDictionary = HashMap();
|
||||
|
||||
final tree = MailboxTree(MailboxNode.root());
|
||||
mailboxesList.forEach((mailbox) {
|
||||
if (mailbox.hasParentId()) {
|
||||
final parentId = mailbox.parentId!;
|
||||
final foundParent = tree.findNode(parentId);
|
||||
if (foundParent != null) {
|
||||
_addDescendant(tree, mailbox, maybeDescendant: mapNotFoundParentMailbox);
|
||||
} else {
|
||||
final siblingTrees = mapNotFoundParentMailbox[mailbox.parentId];
|
||||
if (siblingTrees != null) {
|
||||
mapNotFoundParentMailbox.addAll({
|
||||
parentId: (ListBuilder<PresentationMailbox>(siblingTrees)..add(mailbox)).build()
|
||||
});
|
||||
} else {
|
||||
mapNotFoundParentMailbox.addAll({parentId: (ListBuilder<PresentationMailbox>()..add(mailbox)).build()});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_addDescendant(tree, mailbox, maybeDescendant: mapNotFoundParentMailbox);
|
||||
}
|
||||
mailboxDictionary[mailbox.id] = MailboxNode(mailbox);
|
||||
});
|
||||
mapNotFoundParentMailbox.forEach((_, listMailbox) {
|
||||
listMailbox.forEach((mailbox) {
|
||||
_addDescendant(tree, mailbox);
|
||||
});
|
||||
mailboxesList.forEach((mailbox) {
|
||||
final parentId = mailbox.parentId;
|
||||
final parentNode = mailboxDictionary[parentId];
|
||||
final node = mailboxDictionary[mailbox.id];
|
||||
if (node != null) {
|
||||
if (parentNode != null) {
|
||||
parentNode.addChildNode(node);
|
||||
} else {
|
||||
tree.root.addChildNode(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
return tree;
|
||||
}
|
||||
|
||||
MailboxNode? _addDescendant(
|
||||
MailboxTree tree,
|
||||
PresentationMailbox mailboxChild,
|
||||
{Map<MailboxId, BuiltList<PresentationMailbox>>? maybeDescendant}
|
||||
) {
|
||||
final queue = ListQueue<PresentationMailbox>();
|
||||
queue.addLast(mailboxChild);
|
||||
while (queue.isNotEmpty) {
|
||||
final current = queue.removeFirst();
|
||||
tree.insertNode(current);
|
||||
maybeDescendant?.remove(current.id)?.forEach((child) {
|
||||
queue.addLast(child);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,38 +11,20 @@ void main() {
|
||||
final parentMailbox = PresentationMailbox(MailboxId(Id('1')));
|
||||
final node = MailboxNode(parentMailbox);
|
||||
final childMailbox = PresentationMailbox(MailboxId(Id('11')), parentId: MailboxId(Id('1')));
|
||||
final childNode = node.addChild(childMailbox);
|
||||
node.addChildNode(MailboxNode(childMailbox));
|
||||
|
||||
expect(node.childrenItems.length, equals(1));
|
||||
expect(node.childrenItems[0], equals(childNode));
|
||||
expect(node.childrenItems?.length, equals(1));
|
||||
});
|
||||
|
||||
test('addChild should add new mailbox to a node', () async {
|
||||
test('addChildNode should add other new mailbox to a node', () async {
|
||||
final parentMailbox = PresentationMailbox(MailboxId(Id('1')));
|
||||
final node = MailboxNode(parentMailbox);
|
||||
final childMailbox = PresentationMailbox(MailboxId(Id('11')), parentId: MailboxId(Id('1')));
|
||||
final childNode = node.addChild(childMailbox);
|
||||
node.addChildNode(MailboxNode(childMailbox));
|
||||
final childMailbox2 = PresentationMailbox(MailboxId(Id('12')), parentId: MailboxId(Id('1')));
|
||||
final childNode2 = node.addChild(childMailbox2);
|
||||
node.addChildNode(MailboxNode(childMailbox2));
|
||||
|
||||
expect(node.childrenItems.length, equals(2));
|
||||
expect(node.childrenItems, containsAll({childNode, childNode2}));
|
||||
});
|
||||
|
||||
test('addChild add new mailbox without parentId to a node should return null', () async {
|
||||
final parentMailbox = PresentationMailbox(MailboxId(Id('1')));
|
||||
final node = MailboxNode(parentMailbox);
|
||||
final orphanMailbox = PresentationMailbox(MailboxId(Id('22')));
|
||||
|
||||
expect(node.addChild(orphanMailbox), null);
|
||||
});
|
||||
|
||||
test('addChild add new mailbox with other parentId to a node should return null', () async {
|
||||
final parentMailbox = PresentationMailbox(MailboxId(Id('1')));
|
||||
final node = MailboxNode(parentMailbox);
|
||||
final orphanMailbox = PresentationMailbox(MailboxId(Id('21')), parentId: MailboxId(Id('2')));
|
||||
|
||||
expect(node.addChild(orphanMailbox), null);
|
||||
expect(node.childrenItems!.length, equals(2));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -11,14 +11,14 @@ void main() {
|
||||
final expectedTree = MailboxTree(
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id('root'))),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("1")), parentId: null),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(PresentationMailbox(MailboxId(Id("1_1")), parentId: MailboxId(Id('1')))),
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("1_2")), parentId: MailboxId(Id('1'))),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(PresentationMailbox(MailboxId(Id("1_2_1")), parentId: MailboxId(Id('1_2'))))
|
||||
]
|
||||
),
|
||||
@@ -26,12 +26,12 @@ void main() {
|
||||
),
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("2")), parentId: null),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(PresentationMailbox(MailboxId(Id("2_1")), parentId: MailboxId(Id('2'))),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("2_1_1")), parentId: MailboxId(Id('2_1'))),
|
||||
child: [MailboxNode(PresentationMailbox(MailboxId(Id("2_1_1_1")), parentId: MailboxId(Id('2_1_1'))))]
|
||||
childrenItems: [MailboxNode(PresentationMailbox(MailboxId(Id("2_1_1_1")), parentId: MailboxId(Id('2_1_1'))))]
|
||||
),
|
||||
MailboxNode(PresentationMailbox(MailboxId(Id("2_1_2")), parentId: MailboxId(Id('2_1'))))
|
||||
]
|
||||
@@ -41,16 +41,16 @@ void main() {
|
||||
),
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("3")), parentId: null),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("3_1")), parentId: MailboxId(Id('3'))),
|
||||
child: [
|
||||
childrenItems: [
|
||||
MailboxNode(PresentationMailbox(MailboxId(Id("3_1_1")), parentId: MailboxId(Id('3_1'))))
|
||||
]
|
||||
),
|
||||
MailboxNode(
|
||||
PresentationMailbox(MailboxId(Id("3_2")), parentId: MailboxId(Id('3'))),
|
||||
child: [MailboxNode(PresentationMailbox(MailboxId(Id("3_2_1")), parentId: MailboxId(Id('3_2'))))]
|
||||
childrenItems: [MailboxNode(PresentationMailbox(MailboxId(Id("3_2_1")), parentId: MailboxId(Id('3_2'))))]
|
||||
)
|
||||
]
|
||||
),
|
||||
@@ -103,8 +103,8 @@ void main() {
|
||||
|
||||
final generatedTree = await TreeBuilder().generateMailboxTree(testCase);
|
||||
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems));
|
||||
expect(generatedTree.root.childrenItems[2], equals(expectedTree.root.childrenItems[0]));
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems!));
|
||||
expect(generatedTree.root.childrenItems![2], equals(expectedTree.root.childrenItems![0]));
|
||||
});
|
||||
|
||||
test('list mailbox is not in ordered, parent come first, then grandpa, then children', () async {
|
||||
@@ -128,8 +128,8 @@ void main() {
|
||||
|
||||
final generatedTree = await TreeBuilder().generateMailboxTree(testCase);
|
||||
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems));
|
||||
expect(generatedTree.root.childrenItems[2], equals(expectedTree.root.childrenItems[0]));
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems!));
|
||||
expect(generatedTree.root.childrenItems![2], equals(expectedTree.root.childrenItems![0]));
|
||||
});
|
||||
|
||||
test('list mailbox is not in ordered, children come first, then grandpa, then parent', () async {
|
||||
@@ -153,8 +153,8 @@ void main() {
|
||||
|
||||
final generatedTree = await TreeBuilder().generateMailboxTree(testCase);
|
||||
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems));
|
||||
expect(generatedTree.root.childrenItems[2], equals(expectedTree.root.childrenItems[0]));
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems!));
|
||||
expect(generatedTree.root.childrenItems![2], equals(expectedTree.root.childrenItems![0]));
|
||||
});
|
||||
|
||||
test('list mailbox is not in ordered, children come first, then parent, then grandpa', () async {
|
||||
@@ -178,8 +178,8 @@ void main() {
|
||||
|
||||
final generatedTree = await TreeBuilder().generateMailboxTree(testCase);
|
||||
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems));
|
||||
expect(generatedTree.root.childrenItems[2], equals(expectedTree.root.childrenItems[0]));
|
||||
expect(generatedTree.root.childrenItems, containsAll(expectedTree.root.childrenItems!));
|
||||
expect(generatedTree.root.childrenItems![2], equals(expectedTree.root.childrenItems![0]));
|
||||
});
|
||||
|
||||
test('item have parent but not found in tree will become root child', () async {
|
||||
@@ -204,7 +204,7 @@ void main() {
|
||||
|
||||
final generatedTree = await TreeBuilder().generateMailboxTree(testCase);
|
||||
|
||||
expect(generatedTree.root.childrenItems.length, equals(4));
|
||||
expect(generatedTree.root.childrenItems?.length, equals(4));
|
||||
expect(generatedTree.root.childrenItems,
|
||||
contains(MailboxNode(PresentationMailbox(MailboxId(Id("e3_2_1")), parentId: MailboxId(Id('id42'))))));
|
||||
});
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
|
||||
|
||||
void main() {
|
||||
group('test findNode in mailbox tree', () {
|
||||
late MailboxTree? tree;
|
||||
final level1Node = PresentationMailbox(MailboxId(Id('1')));
|
||||
final level1Node1 = PresentationMailbox(MailboxId(Id('1_1')));
|
||||
final level1Node2 = PresentationMailbox(MailboxId(Id('1_2')));
|
||||
final level2Node1 = PresentationMailbox(MailboxId(Id('2_1')), parentId: MailboxId(Id('1')));
|
||||
final level3Node1 = PresentationMailbox(MailboxId(Id('3_1')), parentId: MailboxId(Id('2_1')));
|
||||
|
||||
setUp(() {
|
||||
tree = MailboxTree(MailboxNode.root());
|
||||
tree!.insertNode(level1Node);
|
||||
tree!.insertNode(level1Node1);
|
||||
tree!.insertNode(level1Node2);
|
||||
tree!.insertNode(level2Node1);
|
||||
tree!.insertNode(level3Node1);
|
||||
});
|
||||
|
||||
test('findNode should find a node in tree at level 1', () {
|
||||
final node1 = tree!.findNode(MailboxId(Id('1')));
|
||||
expect(node1!.item, equals(level1Node));
|
||||
});
|
||||
|
||||
test('findNode should find a node in tree at level 2', () {
|
||||
final node1 = tree!.findNode(MailboxId(Id('1_2')));
|
||||
expect(node1!.item, equals(level1Node2));
|
||||
});
|
||||
|
||||
test('findNode should find a leaf in tree', () {
|
||||
final node1 = tree!.findNode(MailboxId(Id('3_1')));
|
||||
expect(node1!.item, equals(level3Node1));
|
||||
});
|
||||
|
||||
test('findNode should find a node which have children in tree', () {
|
||||
final node1 = tree!.findNode(MailboxId(Id('2_1')));
|
||||
expect(node1!.item, equals(level2Node1));
|
||||
expect(node1.childrenItems.length, equals(1));
|
||||
expect(node1.childrenItems[0].item, equals(level3Node1));
|
||||
});
|
||||
|
||||
test('findNode should not find a node not in tree', () {
|
||||
expect(tree!.findNode(MailboxId(Id('4_1'))), null);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
tree = null;
|
||||
});
|
||||
});
|
||||
|
||||
group('test insertNode in mailbox tree', () {
|
||||
|
||||
test('insertNode should insert a node without parent at level 1', () {
|
||||
final tree = MailboxTree(MailboxNode.root());
|
||||
final mailbox = PresentationMailbox(MailboxId(Id("1")));
|
||||
final insertedNode = tree.insertNode(mailbox);
|
||||
|
||||
expect(tree.root.childrenItems, contains(insertedNode));
|
||||
});
|
||||
|
||||
test('insertNode should insert a node to correctly parent', () {
|
||||
final tree = MailboxTree(MailboxNode.root());
|
||||
final level1Node = PresentationMailbox(MailboxId(Id('1')));
|
||||
final level1Node1 = PresentationMailbox(MailboxId(Id('1_1')));
|
||||
final level1Node2 = PresentationMailbox(MailboxId(Id('1_2')));
|
||||
tree.insertNode(level1Node);
|
||||
tree.insertNode(level1Node1);
|
||||
tree.insertNode(level1Node2);
|
||||
|
||||
final insertedNode = tree.insertNode(PresentationMailbox(MailboxId(Id('2_1_2')), parentId: MailboxId(Id('1_2'))));
|
||||
|
||||
final foundLevel1Node2 = tree.findNode(MailboxId(Id('1_2')));
|
||||
expect(foundLevel1Node2?.childrenItems.length, equals(1));
|
||||
expect(foundLevel1Node2?.childrenItems, contains(insertedNode));
|
||||
});
|
||||
|
||||
test('insertNode should insert a node to root if parent not found', () {
|
||||
final tree = MailboxTree(MailboxNode.root());
|
||||
final level1Node = PresentationMailbox(MailboxId(Id('1')));
|
||||
final level1Node1 = PresentationMailbox(MailboxId(Id('1_1')));
|
||||
final level1Node2 = PresentationMailbox(MailboxId(Id('1_2')));
|
||||
tree.insertNode(level1Node);
|
||||
tree.insertNode(level1Node1);
|
||||
tree.insertNode(level1Node2);
|
||||
|
||||
final insertedNode = tree.insertNode(PresentationMailbox(MailboxId(Id('1_1_1_exp')), parentId: MailboxId(Id('e1_2'))));
|
||||
|
||||
expect(tree.root.childrenItems.length, equals(4));
|
||||
expect(tree.root.childrenItems.map((childNode) => childNode.item).toList(),
|
||||
containsAll({level1Node, level1Node2, level1Node1, insertedNode!.item}));
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user