From 24023af5033a090ae3fce6648754b1454f73a910 Mon Sep 17 00:00:00 2001 From: hieubt Date: Sat, 3 Feb 2024 21:24:50 +0700 Subject: [PATCH 1/2] TF-2316 Fix cannot delete folder with hidden subfolder --- .../delete_multiple_mailbox_interactor.dart | 92 +++++++++++++++++++ .../list_presentation_mailbox_extension.dart | 3 + 2 files changed, 95 insertions(+) diff --git a/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart b/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart index ee09dcc6fb..8deaaf611e 100644 --- a/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart +++ b/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart @@ -1,3 +1,4 @@ +import 'dart:collection'; import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:core/utils/app_logger.dart'; @@ -5,8 +6,14 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:model/extensions/list_presentation_mailbox_extension.dart'; +import 'package:model/extensions/mailbox_extension.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.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'; class DeleteMultipleMailboxInteractor { final MailboxRepository _mailboxRepository; @@ -24,6 +31,24 @@ class DeleteMultipleMailboxInteractor { final currentMailboxState = await _mailboxRepository.getMailboxState(session, accountId); + final mailboxResponses = await _mailboxRepository.getAllMailbox(session, accountId).toList(); + + final listUnsubscribedMailbox = mailboxResponses.expand((mailboxResponse) { + final presentationMailboxes = mailboxResponse.mailboxes + ?.map((mailbox) => mailbox.toPresentationMailbox()).toList() + ?? List.empty(); + return presentationMailboxes.listUnsubscribedMailboxes; + }).toSet(); + + if (listUnsubscribedMailbox.isNotEmpty) { + final unsubscribedTree = buildUnsubscribedMailboxTree(listUnsubscribedMailbox); + mapMailboxIdToDelete = addUnsubscribedSubFolderToDelete( + mapMailboxIdToDelete, + listMailboxIdToDelete, + unsubscribedTree + ); + } + final listResult = await Future.wait( mapMailboxIdToDelete.keys.map((mailboxId) { final mailboxIdsToDelete = mapMailboxIdToDelete[mailboxId]!; @@ -53,4 +78,71 @@ class DeleteMultipleMailboxInteractor { yield Left(DeleteMultipleMailboxFailure(e)); } } + + MailboxTree buildUnsubscribedMailboxTree( + Set listUnsubscribedMailbox, + ) { + Map mailboxDictionary = HashMap(); + final unsubscribedTree = MailboxTree(MailboxNode.root()); + + for (var mailbox in listUnsubscribedMailbox) { + if (mailbox.parentId != null) { + mailboxDictionary[mailbox.id] = MailboxNode(mailbox); + } + } + + for (var mailbox in listUnsubscribedMailbox) { + final parentId = mailbox.parentId; + if (parentId != null) { + final parentNode = mailboxDictionary[parentId]; + final node = mailboxDictionary[mailbox.id]; + if (node != null) { + if (parentNode != null) { + parentNode.addChildNode(node); + } else { + mailboxDictionary[parentId] = MailboxNode(PresentationMailbox(parentId)); + unsubscribedTree.root.addChildNode(mailboxDictionary[parentId]!); + mailboxDictionary[parentId]!.addChildNode(node); + } + } + } + } + + return unsubscribedTree; + } + + Map> addUnsubscribedSubFolderToDelete( + Map> mapMailboxIdToDelete, + List listMailboxIdToDelete, + MailboxTree unsubscribedTree, + ) { + List visitedUnsubscribedMailboxIds = []; + + for (var mailboxId in listMailboxIdToDelete) { + if (visitedUnsubscribedMailboxIds.contains(mailboxId)) { + continue; + } else { + final matchedNode = unsubscribedTree.findNode((node) => node.item.id == mailboxId); + + if (matchedNode != null) { + final descendantIds = matchedNode.descendantsAsList().mailboxIds; + final descendantIdsReversed = descendantIds.reversed.toList(); + descendantIdsReversed.removeLast(); + + if (mapMailboxIdToDelete.containsKey(mailboxId)) { + mapMailboxIdToDelete[mailboxId]!.insertAll(mapMailboxIdToDelete[mailboxId]!.length - 1, descendantIdsReversed); + } else { + for (var listIdToDelete in mapMailboxIdToDelete.values) { + if (listIdToDelete.contains(mailboxId)) { + listIdToDelete.insertAll(listIdToDelete.indexOf(mailboxId), descendantIdsReversed); + } + } + } + visitedUnsubscribedMailboxIds.addAll(descendantIdsReversed); + } + } + } + + return mapMailboxIdToDelete; + } } \ No newline at end of file diff --git a/model/lib/extensions/list_presentation_mailbox_extension.dart b/model/lib/extensions/list_presentation_mailbox_extension.dart index 1ca05f5b98..8493bb37e4 100644 --- a/model/lib/extensions/list_presentation_mailbox_extension.dart +++ b/model/lib/extensions/list_presentation_mailbox_extension.dart @@ -7,6 +7,9 @@ extension ListPresentationMailboxExtension on List { List get listSubscribedMailboxesAndDefaultMailboxes => where((mailbox) => mailbox.isSubscribedMailbox || mailbox.isDefault).toList(); + + List get listUnsubscribedMailboxes => + where((mailbox) => !mailbox.isSubscribedMailbox).toList(); List get listPersonalMailboxes => where((mailbox) => mailbox.isPersonal).toList(); From 05c487ff5e18f597ae0c2019df6923a7cda3b294 Mon Sep 17 00:00:00 2001 From: hieubt Date: Tue, 6 Feb 2024 02:10:31 +0700 Subject: [PATCH 2/2] TF-2316 Write unit test for interactor --- .../delete_multiple_mailbox_interactor.dart | 116 +++---- .../presentation/mailbox_controller.dart | 20 +- .../search_mailbox_controller.dart | 12 +- ...lete_multiple_mailbox_interactor_test.dart | 293 +++++++++++++++++ test/fixtures/mailbox_fixtures.dart | 302 ++++++++++++++++++ 5 files changed, 641 insertions(+), 102 deletions(-) create mode 100644 test/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor_test.dart diff --git a/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart b/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart index 8deaaf611e..1c408f2c66 100644 --- a/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart +++ b/lib/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart @@ -6,14 +6,14 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; -import 'package:model/extensions/list_presentation_mailbox_extension.dart'; import 'package:model/extensions/mailbox_extension.dart'; +import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.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'; +import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart'; class DeleteMultipleMailboxInteractor { final MailboxRepository _mailboxRepository; @@ -23,31 +23,31 @@ class DeleteMultipleMailboxInteractor { Stream> execute( Session session, AccountId accountId, - Map> mapMailboxIdToDelete, - List listMailboxIdToDelete + List listMailboxToDelete ) async* { try { yield Right(LoadingDeleteMultipleMailboxAll()); final currentMailboxState = await _mailboxRepository.getMailboxState(session, accountId); - final mailboxResponses = await _mailboxRepository.getAllMailbox(session, accountId).toList(); - - final listUnsubscribedMailbox = mailboxResponses.expand((mailboxResponse) { - final presentationMailboxes = mailboxResponse.mailboxes - ?.map((mailbox) => mailbox.toPresentationMailbox()).toList() - ?? List.empty(); - return presentationMailboxes.listUnsubscribedMailboxes; - }).toSet(); - - if (listUnsubscribedMailbox.isNotEmpty) { - final unsubscribedTree = buildUnsubscribedMailboxTree(listUnsubscribedMailbox); - mapMailboxIdToDelete = addUnsubscribedSubFolderToDelete( - mapMailboxIdToDelete, - listMailboxIdToDelete, - unsubscribedTree - ); - } + final mailboxResponse = await _mailboxRepository.getAllMailbox(session, accountId).last; + + final listAllMailbox = mailboxResponse.mailboxes + .map((mailbox) => mailbox.toPresentationMailbox()) + .toList(); + + final mailboxTree = buildMailboxTree(listAllMailbox); + final defaultMailboxTree = mailboxTree.value1; + final personalMailboxTree = mailboxTree.value2; + + final mapDescendant = MailboxUtils.generateMapDescendantIdsAndMailboxIdList( + listMailboxToDelete, + defaultMailboxTree, + personalMailboxTree + ); + + final mapMailboxIdToDelete = mapDescendant.value1; + final listMailboxIdToDelete = mapDescendant.value2; final listResult = await Future.wait( mapMailboxIdToDelete.keys.map((mailboxId) { @@ -79,70 +79,40 @@ class DeleteMultipleMailboxInteractor { } } - MailboxTree buildUnsubscribedMailboxTree( - Set listUnsubscribedMailbox, + Tuple2 buildMailboxTree( + List mailboxList, ) { Map mailboxDictionary = HashMap(); - final unsubscribedTree = MailboxTree(MailboxNode.root()); + final defaultTree = MailboxTree(MailboxNode.root()); + final personalTree = MailboxTree(MailboxNode.root()); + final teamMailboxes = MailboxTree(MailboxNode.root()); - for (var mailbox in listUnsubscribedMailbox) { - if (mailbox.parentId != null) { - mailboxDictionary[mailbox.id] = MailboxNode(mailbox); - } + for (var mailbox in mailboxList) { + mailboxDictionary[mailbox.id] = MailboxNode(mailbox); } - for (var mailbox in listUnsubscribedMailbox) { + for (var mailbox in mailboxList) { final parentId = mailbox.parentId; - if (parentId != null) { - final parentNode = mailboxDictionary[parentId]; - final node = mailboxDictionary[mailbox.id]; - if (node != null) { - if (parentNode != null) { - parentNode.addChildNode(node); + final parentNode = mailboxDictionary[parentId]; + final node = mailboxDictionary[mailbox.id]; + if (node != null) { + if (parentNode != null) { + parentNode.addChildNode(node); + } else if (parentId == null) { + MailboxTree tree; + if (mailbox.hasRole()) { + tree = defaultTree; + } else if (mailbox.isPersonal) { + tree = personalTree; } else { - mailboxDictionary[parentId] = MailboxNode(PresentationMailbox(parentId)); - unsubscribedTree.root.addChildNode(mailboxDictionary[parentId]!); - mailboxDictionary[parentId]!.addChildNode(node); + tree = teamMailboxes; } - } - } - } - return unsubscribedTree; - } - - Map> addUnsubscribedSubFolderToDelete( - Map> mapMailboxIdToDelete, - List listMailboxIdToDelete, - MailboxTree unsubscribedTree, - ) { - List visitedUnsubscribedMailboxIds = []; - - for (var mailboxId in listMailboxIdToDelete) { - if (visitedUnsubscribedMailboxIds.contains(mailboxId)) { - continue; - } else { - final matchedNode = unsubscribedTree.findNode((node) => node.item.id == mailboxId); - - if (matchedNode != null) { - final descendantIds = matchedNode.descendantsAsList().mailboxIds; - final descendantIdsReversed = descendantIds.reversed.toList(); - descendantIdsReversed.removeLast(); - - if (mapMailboxIdToDelete.containsKey(mailboxId)) { - mapMailboxIdToDelete[mailboxId]!.insertAll(mapMailboxIdToDelete[mailboxId]!.length - 1, descendantIdsReversed); - } else { - for (var listIdToDelete in mapMailboxIdToDelete.values) { - if (listIdToDelete.contains(mailboxId)) { - listIdToDelete.insertAll(listIdToDelete.indexOf(mailboxId), descendantIdsReversed); - } - } - } - visitedUnsubscribedMailboxIds.addAll(descendantIdsReversed); + tree.root.addChildNode(node); } } } - return mapMailboxIdToDelete; + return Tuple2(defaultTree, personalTree); } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 8452d40b04..b828748766 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -65,7 +65,6 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_catego import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/open_mailbox_view_event.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart'; @@ -738,18 +737,10 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM final session = mailboxDashBoardController.sessionCurrent; if (session != null && accountId != null) { - final tupleMap = MailboxUtils.generateMapDescendantIdsAndMailboxIdList( - [presentationMailbox], - defaultMailboxTree.value, - personalMailboxTree.value); - final mapDescendantIds = tupleMap.value1; - final listMailboxId = tupleMap.value2; - consumeState(_deleteMultipleMailboxInteractor.execute( session, accountId, - mapDescendantIds, - listMailboxId)); + [presentationMailbox])); } else { _deleteMailboxFailure(DeleteMultipleMailboxFailure(null)); } @@ -818,17 +809,10 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM final session = mailboxDashBoardController.sessionCurrent; if (session != null && accountId != null) { - final tupleMap = MailboxUtils.generateMapDescendantIdsAndMailboxIdList( - selectedMailboxList, - defaultMailboxTree.value, - personalMailboxTree.value); - final mapDescendantIds = tupleMap.value1; - final listMailboxId = tupleMap.value2; consumeState(_deleteMultipleMailboxInteractor.execute( session, accountId, - mapDescendantIds, - listMailboxId)); + selectedMailboxList)); } else { _deleteMailboxFailure(DeleteMultipleMailboxFailure(null)); } diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index 275808a626..81dbbdedd1 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -54,7 +54,6 @@ import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_ac import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart'; @@ -419,19 +418,10 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa final session = dashboardController.sessionCurrent; if (session != null && accountId != null) { - final tupleMap = MailboxUtils.generateMapDescendantIdsAndMailboxIdList( - [presentationMailbox], - defaultMailboxTree.value, - personalMailboxTree.value - ); - final mapDescendantIds = tupleMap.value1; - final listMailboxId = tupleMap.value2; - consumeState(_deleteMultipleMailboxInteractor.execute( session, accountId, - mapDescendantIds, - listMailboxId + [presentationMailbox] )); } else { _deleteMailboxFailure(DeleteMultipleMailboxFailure(null)); diff --git a/test/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor_test.dart b/test/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor_test.dart new file mode 100644 index 0000000000..ed1085cac1 --- /dev/null +++ b/test/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor_test.dart @@ -0,0 +1,293 @@ +import 'package:dartz/dartz.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/core/error/error_type.dart'; +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/jmap_mailbox_response.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; +import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart'; +import '../../../../fixtures/account_fixtures.dart'; +import '../../../../fixtures/mailbox_fixtures.dart'; +import '../../../../fixtures/session_fixtures.dart'; +import 'delete_multiple_mailbox_interactor_test.mocks.dart'; + +@GenerateMocks([MailboxRepository]) + +void main() { + late MailboxRepository mailboxRepository; + late DeleteMultipleMailboxInteractor deleteMultipleMailboxInteractor; + + group('[DeleteMultipleMailboxInteractor]', () { + setUp(() { + mailboxRepository = MockMailboxRepository(); + deleteMultipleMailboxInteractor = DeleteMultipleMailboxInteractor(mailboxRepository); + }); + + test('Should execute to delete selected mailbox an all its children included hidden mailbox', () { + final state = jmap.State('s1'); + + when( + mailboxRepository.getMailboxState( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Future.value(state)); + + when( + mailboxRepository.getAllMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Stream.fromIterable({ + JmapMailboxResponse( + mailboxes: [ + MailboxFixtures.inboxMailbox, + MailboxFixtures.sentMailbox, + MailboxFixtures.selectedFolderToDelete, + MailboxFixtures.selectedFolderToDelete_1, + MailboxFixtures.selectedFolderToDelete_2, + ], + state: state, + ), + JmapMailboxResponse( + mailboxes: [ + MailboxFixtures.inboxMailbox, + MailboxFixtures.sentMailbox, + MailboxFixtures.selectedFolderToDelete, + MailboxFixtures.selectedFolderToDelete_1, + MailboxFixtures.selectedFolderToDelete_2, + MailboxFixtures.selectedFolderToDelete_3, + MailboxFixtures.selectedFolderToDelete_4, + MailboxFixtures.selectedFolderToDelete_5, + MailboxFixtures.selectedFolderToDelete_6, + MailboxFixtures.selectedFolderToDelete_7, + MailboxFixtures.selectedFolderToDelete_8, + MailboxFixtures.selectedFolderToDelete_9, + MailboxFixtures.selectedFolderToDelete_10, + ], + state: state, + ), + })); + + when( + mailboxRepository.deleteMultipleMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listDescendantMailboxForSelectedFolder, + ) + ).thenAnswer((_) => Future.value({})); + + when( + mailboxRepository.deleteMultipleMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listDescendantMailboxForSelectedFolder2, + ) + ).thenAnswer((_) => Future.value({})); + + final result = deleteMultipleMailboxInteractor.execute( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listMailboxToDelete + ); + + expect(result, emitsInOrder([ + Right(LoadingDeleteMultipleMailboxAll()), + Right(DeleteMultipleMailboxAllSuccess( + MailboxFixtures.listMailboxIdToDelete, + currentMailboxState: state + )), + ])); + }); + + test('Should execute and yield DeleteMultipleMailboxAllFailure when delete selected mailbox all fail', () { + final state = jmap.State('s1'); + + when( + mailboxRepository.getMailboxState( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Future.value(state)); + + when( + mailboxRepository.getAllMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Stream.fromIterable({ + JmapMailboxResponse( + mailboxes: [ + MailboxFixtures.inboxMailbox, + MailboxFixtures.sentMailbox, + MailboxFixtures.selectedFolderToDelete, + MailboxFixtures.selectedFolderToDelete_1, + MailboxFixtures.selectedFolderToDelete_2, + ], + state: state, + ), + JmapMailboxResponse( + mailboxes: [ + MailboxFixtures.inboxMailbox, + MailboxFixtures.sentMailbox, + MailboxFixtures.selectedFolderToDelete, + MailboxFixtures.selectedFolderToDelete_1, + MailboxFixtures.selectedFolderToDelete_2, + MailboxFixtures.selectedFolderToDelete_3, + MailboxFixtures.selectedFolderToDelete_4, + MailboxFixtures.selectedFolderToDelete_5, + MailboxFixtures.selectedFolderToDelete_6, + MailboxFixtures.selectedFolderToDelete_7, + MailboxFixtures.selectedFolderToDelete_8, + MailboxFixtures.selectedFolderToDelete_9, + MailboxFixtures.selectedFolderToDelete_10, + ], + state: state, + ), + })); + + when( + mailboxRepository.deleteMultipleMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listDescendantMailboxForSelectedFolder, + ) + ).thenAnswer((_) => Future.value({ + Id('folderToDelete'): SetError(ErrorType('error')), + })); + + when( + mailboxRepository.deleteMultipleMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listDescendantMailboxForSelectedFolder2, + ) + ).thenAnswer((_) => Future.value({ + Id('folderToDelete_8'): SetError(ErrorType('error')), + })); + + final result = deleteMultipleMailboxInteractor.execute( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listMailboxToDelete + ); + + expect(result, emitsInOrder([ + Right(LoadingDeleteMultipleMailboxAll()), + Left(DeleteMultipleMailboxAllFailure()), + ])); + }); + + test('Should execute and yield DeleteMultipleMailboxHasSomeSuccess when delete selected mailbox has some fail', () { + final state = jmap.State('s1'); + + when( + mailboxRepository.getMailboxState( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Future.value(state)); + + when( + mailboxRepository.getAllMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Stream.fromIterable({ + JmapMailboxResponse( + mailboxes: [ + MailboxFixtures.inboxMailbox, + MailboxFixtures.sentMailbox, + MailboxFixtures.selectedFolderToDelete, + MailboxFixtures.selectedFolderToDelete_1, + MailboxFixtures.selectedFolderToDelete_2, + ], + state: state, + ), + JmapMailboxResponse( + mailboxes: [ + MailboxFixtures.inboxMailbox, + MailboxFixtures.sentMailbox, + MailboxFixtures.selectedFolderToDelete, + MailboxFixtures.selectedFolderToDelete_1, + MailboxFixtures.selectedFolderToDelete_2, + MailboxFixtures.selectedFolderToDelete_3, + MailboxFixtures.selectedFolderToDelete_4, + MailboxFixtures.selectedFolderToDelete_5, + MailboxFixtures.selectedFolderToDelete_6, + MailboxFixtures.selectedFolderToDelete_7, + MailboxFixtures.selectedFolderToDelete_8, + MailboxFixtures.selectedFolderToDelete_9, + MailboxFixtures.selectedFolderToDelete_10, + ], + state: state, + ), + })); + + when( + mailboxRepository.deleteMultipleMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listDescendantMailboxForSelectedFolder, + ) + ).thenAnswer((_) => Future.value({ + Id('folderToDelete'): SetError(ErrorType('error')), + })); + + when( + mailboxRepository.deleteMultipleMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listDescendantMailboxForSelectedFolder2, + ) + ).thenAnswer((_) => Future.value({})); + + final result = deleteMultipleMailboxInteractor.execute( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listMailboxToDelete + ); + + expect(result, emitsInOrder([ + Right(LoadingDeleteMultipleMailboxAll()), + Right(DeleteMultipleMailboxHasSomeSuccess( + MailboxFixtures.listMailboxIdToDelete, + currentMailboxState: state + )), + ])); + }); + + test('Should execute and yield DeleteMultipleMailboxFailure when getAllMailbox fail', () { + final state = jmap.State('s1'); + + when( + mailboxRepository.getMailboxState( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenAnswer((_) => Future.value(state)); + + when( + mailboxRepository.getAllMailbox( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId + ) + ).thenThrow('error'); + + final result = deleteMultipleMailboxInteractor.execute( + SessionFixtures.aliceSession, + AccountFixtures.aliceAccountId, + MailboxFixtures.listMailboxToDelete + ); + + expect(result, emitsInOrder([ + Right(LoadingDeleteMultipleMailboxAll()), + Left(DeleteMultipleMailboxFailure('error')), + ])); + }); + }); +} \ No newline at end of file diff --git a/test/fixtures/mailbox_fixtures.dart b/test/fixtures/mailbox_fixtures.dart index a1796f5e6a..f4071e45ef 100644 --- a/test/fixtures/mailbox_fixtures.dart +++ b/test/fixtures/mailbox_fixtures.dart @@ -2,6 +2,8 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_rights.dart'; +import 'package:model/extensions/mailbox_extension.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; class MailboxFixtures { static final inboxMailbox = Mailbox( @@ -100,4 +102,304 @@ class MailboxFixtures { static final mailboxB = Mailbox(id: MailboxId(Id('B'))); static final mailboxC = Mailbox(id: MailboxId(Id('C'))); static final mailboxD = Mailbox(id: MailboxId(Id('D'))); + + static final selectedFolderToDelete = Mailbox( + id: MailboxId(Id('folderToDelete')), + name: MailboxName('folderToDelete'), + parentId: null, + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(true) + ); + + static final selectedFolderToDelete_1 = Mailbox( + id: MailboxId(Id('folderToDelete_1')), + name: MailboxName('folderToDelete_1'), + parentId: MailboxId(Id("folderToDelete")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_2 = Mailbox( + id: MailboxId(Id('folderToDelete_2')), + name: MailboxName('folderToDelete_2'), + parentId: MailboxId(Id("folderToDelete_1")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_3 = Mailbox( + id: MailboxId(Id('folderToDelete_3')), + name: MailboxName('folderToDelete_3'), + parentId: MailboxId(Id("folderToDelete")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(true) + ); + + static final selectedFolderToDelete_4 = Mailbox( + id: MailboxId(Id('folderToDelete_4')), + name: MailboxName('folderToDelete_4'), + parentId: MailboxId(Id("folderToDelete_3")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_5 = Mailbox( + id: MailboxId(Id('folderToDelete_5')), + name: MailboxName('folderToDelete_5'), + parentId: MailboxId(Id("folderToDelete_3")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_6 = Mailbox( + id: MailboxId(Id('folderToDelete_6')), + name: MailboxName('folderToDelete_6'), + parentId: MailboxId(Id("folderToDelete_5")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_7 = Mailbox( + id: MailboxId(Id('folderToDelete_7')), + name: MailboxName('folderToDelete_7'), + parentId: MailboxId(Id("folderToDelete_6")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_8 = Mailbox( + id: MailboxId(Id('folderToDelete_8')), + name: MailboxName('folderToDelete_8'), + parentId: null, + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(true) + ); + + static final selectedFolderToDelete_9 = Mailbox( + id: MailboxId(Id('folderToDelete_9')), + name: MailboxName('folderToDelete_9'), + parentId: MailboxId(Id("folderToDelete_8")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final selectedFolderToDelete_10 = Mailbox( + id: MailboxId(Id('folderToDelete_10')), + name: MailboxName('folderToDelete_10'), + parentId: MailboxId(Id("folderToDelete_8")), + role: null, + sortOrder: SortOrder(sortValue: 1000), + totalEmails: TotalEmails(UnsignedInt(123)), + unreadEmails: UnreadEmails(UnsignedInt(12)), + totalThreads: TotalThreads(UnsignedInt(123)), + unreadThreads: UnreadThreads(UnsignedInt(12)), + myRights: MailboxRights( + true, + true, + true, + true, + true, + true, + true, + true, + true + ), + isSubscribed: IsSubscribed(false) + ); + + static final listMailboxIdToDelete = [ + MailboxId(Id('folderToDelete_7')), + MailboxId(Id('folderToDelete_6')), + MailboxId(Id('folderToDelete_5')), + MailboxId(Id('folderToDelete_4')), + MailboxId(Id('folderToDelete_3')), + MailboxId(Id('folderToDelete_2')), + MailboxId(Id('folderToDelete_1')), + MailboxId(Id('folderToDelete')), + MailboxId(Id('folderToDelete_10')), + MailboxId(Id('folderToDelete_9')), + MailboxId(Id('folderToDelete_8')) + ]; + + static final listDescendantMailboxForSelectedFolder = [ + MailboxId(Id('folderToDelete_7')), + MailboxId(Id('folderToDelete_6')), + MailboxId(Id('folderToDelete_5')), + MailboxId(Id('folderToDelete_4')), + MailboxId(Id('folderToDelete_3')), + MailboxId(Id('folderToDelete_2')), + MailboxId(Id('folderToDelete_1')), + MailboxId(Id('folderToDelete')), + ]; + + static final listDescendantMailboxForSelectedFolder2 = [ + MailboxId(Id('folderToDelete_10')), + MailboxId(Id('folderToDelete_9')), + MailboxId(Id('folderToDelete_8')) + ]; + + static final listMailboxToDelete = [ + selectedFolderToDelete.toPresentationMailbox(), + selectedFolderToDelete_8.toPresentationMailbox() + ]; } \ No newline at end of file