chromium/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabsSettingsUnitTest.java

// 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.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Activity;

import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle.State;
import androidx.preference.Preference;
import androidx.test.core.app.ActivityScenario;
import androidx.test.filters.SmallTest;

import org.junit.After;
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.shared_preferences.SharedPreferencesManager;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.TabArchiveSettings;
import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncFeatures;
import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncFeaturesJni;
import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.components.user_prefs.UserPrefsJni;
import org.chromium.ui.base.TestActivity;

import java.util.concurrent.TimeUnit;

/** Unit tests for {@link TabsSettings}. */
@RunWith(BaseRobolectricTestRunner.class)
@EnableFeatures({
    ChromeFeatureList.TAB_GROUP_CREATION_DIALOG_ANDROID,
    ChromeFeatureList.TAB_GROUP_PARITY_ANDROID,
    ChromeFeatureList.TAB_GROUP_SYNC_ANDROID,
    ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH
})
@DisableFeatures(ChromeFeatureList.ANDROID_TAB_DECLUTTER)
public class TabsSettingsUnitTest {
    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
    @Rule public JniMocker mJniMocker = new JniMocker();

    private ActivityScenario<TestActivity> mActivityScenario;
    private TestActivity mActivity;
    private SharedPreferencesManager mSharedPreferencesManager;

    @Mock private Profile mProfileMock;
    @Mock private UserPrefs.Natives mUserPrefsJniMock;
    @Mock private PrefService mPrefServiceMock;
    @Mock private TabGroupSyncFeatures.Natives mTabGroupSyncFeaturesJniMock;

    @Before
    public void setUp() {
        mJniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock);
        when(mUserPrefsJniMock.get(mProfileMock)).thenReturn(mPrefServiceMock);
        mJniMocker.mock(TabGroupSyncFeaturesJni.TEST_HOOKS, mTabGroupSyncFeaturesJniMock);
        doReturn(true).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfileMock);

        mActivityScenario = ActivityScenario.launch(TestActivity.class);
        mActivityScenario.onActivity(this::onActivity);
        mSharedPreferencesManager = ChromeSharedPreferences.getInstance();
    }

    @After
    public void tearDown() {
        mSharedPreferencesManager.removeKey(ChromePreferenceKeys.SHOW_TAB_GROUP_CREATION_DIALOG);
        mActivityScenario.close();
    }

    private void onActivity(Activity activity) {
        mActivity = (TestActivity) activity;
    }

    private TabsSettings launchFragment() {
        FragmentManager fragmentManager = mActivity.getSupportFragmentManager();
        TabsSettings tabsSettings =
                (TabsSettings)
                        fragmentManager
                                .getFragmentFactory()
                                .instantiate(
                                        TabsSettings.class.getClassLoader(),
                                        TabsSettings.class.getName());
        tabsSettings.setProfile(mProfileMock);
        fragmentManager.beginTransaction().replace(android.R.id.content, tabsSettings).commit();
        mActivityScenario.moveToState(State.STARTED);

        assertEquals(
                mActivity.getString(R.string.tabs_settings_title),
                tabsSettings.getPageTitle().get());
        return tabsSettings;
    }

    @Test
    @SmallTest
    public void testLaunchTabsSettingsAutoOpenSyncedTabGroupsEnabled() {
        when(mPrefServiceMock.getBoolean(Pref.AUTO_OPEN_SYNCED_TAB_GROUPS)).thenReturn(true);

        var histogramWatcher =
                HistogramWatcher.newSingleRecordWatcher(
                        "Tabs.AutoOpenSyncedTabGroupsSwitch.ToggledToState", false);
        TabsSettings tabsSettings = launchFragment();
        ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch =
                tabsSettings.findPreference(TabsSettings.PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH);
        assertEquals(
                mActivity.getString(R.string.auto_open_synced_tab_groups_summary),
                autoOpenSyncedTabGroupsSwitch.getSummary());
        assertTrue(autoOpenSyncedTabGroupsSwitch.isChecked());

        autoOpenSyncedTabGroupsSwitch.onClick();

        assertFalse(autoOpenSyncedTabGroupsSwitch.isChecked());
        verify(mPrefServiceMock).setBoolean(Pref.AUTO_OPEN_SYNCED_TAB_GROUPS, false);
        histogramWatcher.assertExpected();
    }

    @Test
    @SmallTest
    public void testLaunchTabsSettingsAutoOpenSyncedTabGroupsDisabled() {
        when(mPrefServiceMock.getBoolean(Pref.AUTO_OPEN_SYNCED_TAB_GROUPS)).thenReturn(false);

        var histogramWatcher =
                HistogramWatcher.newSingleRecordWatcher(
                        "Tabs.AutoOpenSyncedTabGroupsSwitch.ToggledToState", true);
        TabsSettings tabsSettings = launchFragment();
        ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch =
                tabsSettings.findPreference(TabsSettings.PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH);
        assertEquals(
                mActivity.getString(R.string.auto_open_synced_tab_groups_summary),
                autoOpenSyncedTabGroupsSwitch.getSummary());
        assertFalse(autoOpenSyncedTabGroupsSwitch.isChecked());

        autoOpenSyncedTabGroupsSwitch.onClick();

        assertTrue(autoOpenSyncedTabGroupsSwitch.isChecked());
        verify(mPrefServiceMock).setBoolean(Pref.AUTO_OPEN_SYNCED_TAB_GROUPS, true);
        histogramWatcher.assertExpected();
    }

    @Test
    @SmallTest
    @DisableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_ANDROID)
    public void testTabGroupSyncSettingsHiddenWhenFeatureOff() {
        doReturn(false).when(mTabGroupSyncFeaturesJniMock).isTabGroupSyncEnabled(mProfileMock);
        TabsSettings tabsSettings = launchFragment();
        ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch =
                tabsSettings.findPreference(TabsSettings.PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH);
        assertFalse(autoOpenSyncedTabGroupsSwitch.isVisible());
    }

    @Test
    @SmallTest
    @DisableFeatures(ChromeFeatureList.TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH)
    public void testTabGroupSyncSettingsHiddenWhenKillswitchEnabled() {
        TabsSettings tabsSettings = launchFragment();
        ChromeSwitchPreference autoOpenSyncedTabGroupsSwitch =
                tabsSettings.findPreference(TabsSettings.PREF_AUTO_OPEN_SYNCED_TAB_GROUPS_SWITCH);
        assertFalse(autoOpenSyncedTabGroupsSwitch.isVisible());
    }

    @Test
    @SmallTest
    public void testLaunchTabsSettingsGroupCreationDialogEnabled() {
        TabGroupModelFilter.SHOW_TAB_GROUP_CREATION_DIALOG_SETTING.setForTesting(true);

        var histogramWatcher =
                HistogramWatcher.newSingleRecordWatcher(
                        "TabGroups.ShowTabGroupCreationDialogSwitch.ToggledToState", false);
        mSharedPreferencesManager.writeBoolean(
                ChromePreferenceKeys.SHOW_TAB_GROUP_CREATION_DIALOG, true);

        TabsSettings tabsSettings = launchFragment();
        ChromeSwitchPreference showTabGroupCreationDialogSwitch =
                tabsSettings.findPreference(
                        TabsSettings.PREF_SHOW_TAB_GROUP_CREATION_DIALOG_SWITCH);
        assertTrue(showTabGroupCreationDialogSwitch.isVisible());
        assertEquals(
                mActivity.getString(R.string.tab_group_creation_dialog_show_setting_text),
                showTabGroupCreationDialogSwitch.getSummary());
        assertTrue(showTabGroupCreationDialogSwitch.isChecked());
        assertTrue(
                mSharedPreferencesManager.readBoolean(
                        ChromePreferenceKeys.SHOW_TAB_GROUP_CREATION_DIALOG, true));

        showTabGroupCreationDialogSwitch.onClick();

        assertFalse(showTabGroupCreationDialogSwitch.isChecked());
        assertFalse(
                mSharedPreferencesManager.readBoolean(
                        ChromePreferenceKeys.SHOW_TAB_GROUP_CREATION_DIALOG, true));
        histogramWatcher.assertExpected();
    }

    @Test
    @SmallTest
    @DisableFeatures(ChromeFeatureList.TAB_GROUP_PARITY_ANDROID)
    public void testTabGroupCreationDialogSettingsHiddenWhenFeatureOff() {
        TabsSettings tabsSettings = launchFragment();
        ChromeSwitchPreference showTabGroupCreationDialogSwitch =
                tabsSettings.findPreference(
                        TabsSettings.PREF_SHOW_TAB_GROUP_CREATION_DIALOG_SWITCH);
        assertFalse(showTabGroupCreationDialogSwitch.isVisible());
    }

    @Test
    @SmallTest
    @DisableFeatures(ChromeFeatureList.ANDROID_TAB_DECLUTTER)
    public void testArchiveSettingsHiddenWhenFeatureOff() {
        TabsSettings tabsSettings = launchFragment();
        Preference archiveSettinsEntryPoint =
                tabsSettings.findPreference(TabsSettings.PREF_TAB_ARCHIVE_SETTINGS);
        assertFalse(archiveSettinsEntryPoint.isVisible());
    }

    @Test
    @SmallTest
    @EnableFeatures(ChromeFeatureList.ANDROID_TAB_DECLUTTER)
    public void testArchiveSettingsTitleAndSummary() {
        TabArchiveSettings archiveSettings =
                new TabArchiveSettings(ChromeSharedPreferences.getInstance());
        archiveSettings.setArchiveEnabled(true);
        archiveSettings.setArchiveTimeDeltaHours((int) TimeUnit.DAYS.toHours(14));

        TabsSettings tabsSettings = launchFragment();
        Preference archiveSettinsEntryPoint =
                tabsSettings.findPreference(TabsSettings.PREF_TAB_ARCHIVE_SETTINGS);
        assertTrue(archiveSettinsEntryPoint.isVisible());

        assertEquals("Inactive", archiveSettinsEntryPoint.getTitle());
        assertEquals("After 14 days", archiveSettinsEntryPoint.getSummary());
    }
}