// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.chromium.ui.test.util.MockitoHelper.doCallback;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.Callback;
import org.chromium.base.Token;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.chrome.browser.data_sharing.DataSharingServiceFactory;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory;
import org.chromium.chrome.browser.tabmodel.TabClosureParams;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
import org.chromium.chrome.browser.tasks.tab_management.ActionConfirmationManager.ConfirmationResult;
import org.chromium.components.data_sharing.DataSharingService;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.components.tab_group_sync.LocalTabGroupId;
import org.chromium.components.tab_group_sync.SavedTabGroup;
import org.chromium.components.tab_group_sync.TabGroupSyncService;
import java.util.List;
/** Unit tests for {@link TabUiUtils}. */
@RunWith(BaseRobolectricTestRunner.class)
@EnableFeatures(ChromeFeatureList.DATA_SHARING)
public class TabUiUtilsUnitTest {
private static final int TAB_ID = 123;
private static final int ROOT_ID = TAB_ID;
private static final String GROUP_TITLE = "My Group";
private static final String COLLABORATION_ID1 = "A";
private static final String GAIA_ID = "Z";
private static final String EMAIL = "[email protected]";
private static final Token TAB_GROUP_TOKEN = Token.createRandom();
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private TabModel mTabModel;
@Mock private TabGroupModelFilter mFilter;
@Mock private ActionConfirmationManager mActionConfirmationManager;
@Mock private Tab mTab;
@Mock private Profile mProfile;
@Mock private IdentityServicesProvider mIdentityServicesProvider;
@Mock private IdentityManager mIdentityManager;
@Mock private TabGroupSyncService mTabGroupSyncService;
@Mock private DataSharingService mDataSharingService;
@Mock private Callback<Boolean> mDidCloseTabsCallback;
private List<Tab> mTabsToClose;
@Before
public void setUp() {
mTabsToClose = List.of(mTab);
when(mFilter.getTabModel()).thenReturn(mTabModel);
when(mFilter.isIncognitoBranded()).thenReturn(false);
when(mTabModel.getTabById(TAB_ID)).thenReturn(mTab);
when(mTab.getRootId()).thenReturn(ROOT_ID);
when(mFilter.getRelatedTabListForRootId(ROOT_ID)).thenReturn(mTabsToClose);
when(mTabModel.getTabById(TAB_ID)).thenReturn(mTab);
when(mTab.isClosing()).thenReturn(false);
when(mTab.getId()).thenReturn(TAB_ID);
when(mTab.getTabGroupId()).thenReturn(TAB_GROUP_TOKEN);
when(mTabModel.getProfile()).thenReturn(mProfile);
IdentityServicesProvider.setInstanceForTests(mIdentityServicesProvider);
when(mIdentityServicesProvider.getIdentityManager(any())).thenReturn(mIdentityManager);
TabGroupSyncServiceFactory.setForTesting(mTabGroupSyncService);
DataSharingServiceFactory.setForTesting(mDataSharingService);
}
@Test
public void testCloseTabGroup_Incognito() {
boolean hideTabGroups = false;
when(mFilter.isIncognitoBranded()).thenReturn(true);
TabUiUtils.closeTabGroup(
mFilter,
mActionConfirmationManager,
TAB_ID,
hideTabGroups,
/* isSyncEnabled= */ true,
mDidCloseTabsCallback);
verify(mFilter)
.closeTabs(
TabClosureParams.closeTabs(mTabsToClose)
.hideTabGroups(hideTabGroups)
.build());
verify(mDidCloseTabsCallback).onResult(true);
}
@Test
public void testCloseTabGroup_Hide() {
boolean hideTabGroups = true;
TabUiUtils.closeTabGroup(
mFilter,
mActionConfirmationManager,
TAB_ID,
hideTabGroups,
/* isSyncEnabled= */ true,
mDidCloseTabsCallback);
verify(mFilter)
.closeTabs(TabClosureParams.closeTabs(mTabsToClose).hideTabGroups(true).build());
verify(mDidCloseTabsCallback).onResult(true);
}
@Test
public void testCloseTabGroup_Delete_Positive() {
boolean hideTabGroups = false;
doCallback(
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processDeleteGroupAttempt(any());
TabUiUtils.closeTabGroup(
mFilter,
mActionConfirmationManager,
TAB_ID,
hideTabGroups,
/* isSyncEnabled= */ true,
mDidCloseTabsCallback);
verify(mActionConfirmationManager).processDeleteGroupAttempt(any());
verify(mFilter)
.closeTabs(
TabClosureParams.closeTabs(mTabsToClose)
.allowUndo(false)
.hideTabGroups(hideTabGroups)
.build());
verify(mDidCloseTabsCallback).onResult(true);
}
@Test
public void testCloseTabGroup_Delete_Positive_Immediate() {
boolean hideTabGroups = false;
doCallback(
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.IMMEDIATE_CONTINUE))
.when(mActionConfirmationManager)
.processDeleteGroupAttempt(any());
TabUiUtils.closeTabGroup(
mFilter,
mActionConfirmationManager,
TAB_ID,
hideTabGroups,
/* isSyncEnabled= */ true,
mDidCloseTabsCallback);
verify(mActionConfirmationManager).processDeleteGroupAttempt(any());
verify(mFilter)
.closeTabs(
TabClosureParams.closeTabs(mTabsToClose)
.hideTabGroups(hideTabGroups)
.build());
verify(mDidCloseTabsCallback).onResult(true);
}
@Test
public void testCloseTabGroup_Delete_Negative() {
boolean hideTabGroups = false;
doCallback(
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_NEGATIVE))
.when(mActionConfirmationManager)
.processDeleteGroupAttempt(any());
TabUiUtils.closeTabGroup(
mFilter,
mActionConfirmationManager,
TAB_ID,
hideTabGroups,
/* isSyncEnabled= */ true,
mDidCloseTabsCallback);
verify(mActionConfirmationManager).processDeleteGroupAttempt(any());
verify(mFilter, never()).closeTabs(any());
verify(mDidCloseTabsCallback).onResult(false);
}
@Test
public void testDeleteSharedTabGroup_Positive() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processDeleteSharedGroupAttempt(any(), any());
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
TabUiUtils.deleteSharedTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager).processDeleteSharedGroupAttempt(eq(GROUP_TITLE), any());
verify(mDataSharingService).deleteGroup(eq(COLLABORATION_ID1), any());
}
@Test
public void testDeleteSharedTabGroup_Negative() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_NEGATIVE))
.when(mActionConfirmationManager)
.processDeleteSharedGroupAttempt(any(), any());
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
TabUiUtils.deleteSharedTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager).processDeleteSharedGroupAttempt(eq(GROUP_TITLE), any());
verify(mDataSharingService, never()).deleteGroup(any(), any());
}
@Test
public void testDeleteSharedTabGroup_NullTab() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processDeleteSharedGroupAttempt(any(), any());
when(mTabModel.getTabById(anyInt())).thenReturn(null);
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
TabUiUtils.deleteSharedTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processDeleteSharedGroupAttempt(any(), any());
}
@Test
public void testDeleteSharedTabGroup_NullTabGroupId() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processDeleteSharedGroupAttempt(any(), any());
when(mTab.getTabGroupId()).thenReturn(null);
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
TabUiUtils.deleteSharedTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processDeleteSharedGroupAttempt(any(), any());
}
@Test
public void testDeleteSharedTabGroup_NullSavedTabGroup() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processDeleteSharedGroupAttempt(any(), any());
TabUiUtils.deleteSharedTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processDeleteSharedGroupAttempt(any(), any());
}
@Test
public void testDeleteSharedTabGroup_NullCollaborationId() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processDeleteSharedGroupAttempt(any(), any());
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = null;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
TabUiUtils.deleteSharedTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processDeleteSharedGroupAttempt(any(), any());
}
@Test
public void testLeaveTabGroup_Positive() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processLeaveGroupAttempt(any(), any());
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
CoreAccountInfo coreAccountInfo = CoreAccountInfo.createFromEmailAndGaiaId(EMAIL, GAIA_ID);
when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(coreAccountInfo);
TabUiUtils.leaveTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager).processLeaveGroupAttempt(eq(GROUP_TITLE), any());
verify(mDataSharingService).removeMember(eq(COLLABORATION_ID1), eq(EMAIL), any());
}
@Test
public void testLeaveTabGroup_Negative() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_NEGATIVE))
.when(mActionConfirmationManager)
.processLeaveGroupAttempt(any(), any());
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
CoreAccountInfo coreAccountInfo = CoreAccountInfo.createFromEmailAndGaiaId(EMAIL, GAIA_ID);
when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(coreAccountInfo);
TabUiUtils.leaveTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager).processLeaveGroupAttempt(eq(GROUP_TITLE), any());
verify(mDataSharingService, never()).removeMember(any(), any(), any());
}
@Test
public void testLeaveTabGroup_NullTab() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processLeaveGroupAttempt(any(), any());
when(mTabModel.getTabById(anyInt())).thenReturn(null);
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
CoreAccountInfo coreAccountInfo = CoreAccountInfo.createFromEmailAndGaiaId(EMAIL, GAIA_ID);
when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(coreAccountInfo);
TabUiUtils.leaveTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processLeaveGroupAttempt(any(), any());
}
@Test
public void testLeaveTabGroup_NullSavedTabGroup() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processLeaveGroupAttempt(any(), any());
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(null);
CoreAccountInfo coreAccountInfo = CoreAccountInfo.createFromEmailAndGaiaId(EMAIL, GAIA_ID);
when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(coreAccountInfo);
TabUiUtils.leaveTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processLeaveGroupAttempt(any(), any());
}
@Test
public void testLeaveTabGroup_NullCoreAccountInfo() {
doCallback(
1,
(Callback<Integer> resultCallback) ->
resultCallback.onResult(ConfirmationResult.CONFIRMATION_POSITIVE))
.when(mActionConfirmationManager)
.processLeaveGroupAttempt(any(), any());
SavedTabGroup savedTabGroup = new SavedTabGroup();
savedTabGroup.title = GROUP_TITLE;
savedTabGroup.collaborationId = COLLABORATION_ID1;
when(mTabGroupSyncService.getGroup(any(LocalTabGroupId.class))).thenReturn(savedTabGroup);
when(mIdentityManager.getPrimaryAccountInfo(anyInt())).thenReturn(null);
TabUiUtils.leaveTabGroup(mFilter, mActionConfirmationManager, TAB_ID);
verify(mActionConfirmationManager, never()).processLeaveGroupAttempt(any(), any());
}
}