chromium/chrome/browser/privacy_guide/android/junit/src/org/chromium/chrome/browser/privacy_guide/HistorySyncFragmentTest.java

// Copyright 2022 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.privacy_guide;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.os.Bundle;
import android.widget.TextView;

import androidx.fragment.app.testing.FragmentScenario;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

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.UserActionTester;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.sync.SyncServiceFactory;
import org.chromium.components.browser_ui.widget.MaterialSwitchWithText;
import org.chromium.components.sync.SyncService;
import org.chromium.components.sync.UserSelectableType;

import java.util.HashSet;
import java.util.Set;

/** JUnit tests of the class {@link HistorySyncFragment}. */
@RunWith(BaseRobolectricTestRunner.class)
@EnableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
public class HistorySyncFragmentTest {
    private static final String CHANGE_HISTORY_SYNC_ON_USER_ACTION =
            "Settings.PrivacyGuide.ChangeHistorySyncOn";
    private static final String CHANGE_HISTORY_SYNC_OFF_USER_ACTION =
            "Settings.PrivacyGuide.ChangeHistorySyncOff";

    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();

    @Mock private SyncService mSyncService;

    @Captor private ArgumentCaptor<Set<Integer>> mSetCaptor;

    private FragmentScenario mScenario;
    private MaterialSwitchWithText mHistorySyncButton;
    private final UserActionTester mActionTester = new UserActionTester();

    @Before
    public void setUp() {
        SyncServiceFactory.setInstanceForTesting(mSyncService);
    }

    @After
    public void tearDown() {
        if (mScenario != null) {
            mScenario.close();
        }
        mActionTester.tearDown();
    }

    private void initFragmentWithSyncState(boolean syncAll, boolean historySync) {
        initSyncState(syncAll, historySync);
        mScenario =
                FragmentScenario.launchInContainer(
                        HistorySyncFragment.class, Bundle.EMPTY, R.style.Theme_MaterialComponents);
        mScenario.onFragment(
                fragment ->
                        mHistorySyncButton =
                                fragment.getView().findViewById(R.id.history_sync_switch));
    }

    private void initSyncState(boolean syncAll, boolean historySync) {
        // With the flag enabled, hasKeepEverythingSynced() will always return false.
        if (!ChromeFeatureList.isEnabled(
                ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS)) {
            when(mSyncService.hasKeepEverythingSynced()).thenReturn(syncAll);

            if (syncAll) {
                historySync = true;
            }
        }

        Set<Integer> syncTypes = new HashSet<>();
        if (historySync) {
            syncTypes.add(UserSelectableType.HISTORY);
        }
        when(mSyncService.getSelectedTypes()).thenReturn(syncTypes);
    }

    @Test
    public void testIsSwitchOffWhenHistorySyncOff() {
        initFragmentWithSyncState(false, false);
        assertFalse(mHistorySyncButton.isChecked());
    }

    @Test
    public void testIsSwitchOnWhenHistorySyncOnSyncAllOff() {
        initFragmentWithSyncState(false, true);
        assertTrue(mHistorySyncButton.isChecked());
    }

    @Test
    public void testIsSwitchOnWhenHistorySyncOnSyncAllOn() {
        initFragmentWithSyncState(true, true);
        assertTrue(mHistorySyncButton.isChecked());
    }

    @Test
    @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
    public void testTurnHistorySyncOffWhenSyncAllOn() {
        initFragmentWithSyncState(true, true);
        mHistorySyncButton.performClick();
        verify(mSyncService).setSelectedTypes(eq(false), mSetCaptor.capture());
        assertFalse(mSetCaptor.getValue().contains(UserSelectableType.HISTORY));
    }

    @Test
    @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
    public void testTurnHistorySyncOn() {
        initFragmentWithSyncState(false, false);
        mHistorySyncButton.performClick();
        verify(mSyncService).setSelectedTypes(eq(false), mSetCaptor.capture());
        assertTrue(mSetCaptor.getValue().contains(UserSelectableType.HISTORY));
    }

    @Test
    @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
    public void testTurnHistorySyncOffThenOnWhenSyncAllOn() {
        initFragmentWithSyncState(true, true);
        mHistorySyncButton.performClick();
        mHistorySyncButton.performClick();
        verify(mSyncService).setSelectedTypes(eq(true), mSetCaptor.capture());
        assertTrue(mSetCaptor.getValue().contains(UserSelectableType.HISTORY));
    }

    @Test
    @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
    public void testTurnHistorySyncOffThenOnWhenSyncAllOff() {
        initFragmentWithSyncState(false, true);
        mHistorySyncButton.performClick();
        mHistorySyncButton.performClick();
        verify(mSyncService, times(2)).setSelectedTypes(eq(false), mSetCaptor.capture());
        assertTrue(mSetCaptor.getAllValues().get(1).contains(UserSelectableType.HISTORY));
    }

    @Test
    public void testToggleOn() throws Exception {
        initFragmentWithSyncState(false, false);
        assertFalse(mHistorySyncButton.isChecked());

        mHistorySyncButton.performClick();
        verify(mSyncService, times(1)).setSelectedType(eq(UserSelectableType.HISTORY), eq(true));
        verify(mSyncService, times(1)).setSelectedType(eq(UserSelectableType.TABS), eq(true));
    }

    @Test
    public void testToggleOff() throws Exception {
        initFragmentWithSyncState(false, true);
        assertTrue(mHistorySyncButton.isChecked());

        mHistorySyncButton.performClick();
        verify(mSyncService, times(1)).setSelectedType(eq(UserSelectableType.HISTORY), eq(false));
        verify(mSyncService, times(1)).setSelectedType(eq(UserSelectableType.TABS), eq(false));
    }

    @Test
    public void testTurnHistorySyncOn_changeHistorySyncOnUserAction() {
        initFragmentWithSyncState(false, false);
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_ON_USER_ACTION));
    }

    @Test
    public void testTurnHistorySyncOffWhenSyncAllOn_changeHistorySyncOffUserAction() {
        initFragmentWithSyncState(true, true);
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_OFF_USER_ACTION));
    }

    @Test
    public void testTurnHistorySyncOffWhenSyncAllOff_changeHistorySyncOffUserAction() {
        initFragmentWithSyncState(false, true);
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_OFF_USER_ACTION));
    }

    @Test
    public void testTurnHistorySyncOffThenOnWhenSyncAllOn_changeHistorySyncOffOnUserAction() {
        initFragmentWithSyncState(true, true);
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_OFF_USER_ACTION));
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_ON_USER_ACTION));
    }

    @Test
    public void testTurnHistorySyncOffThenOnWhenSyncAllOff_changeHistorySyncOffOnUserAction() {
        initFragmentWithSyncState(false, true);
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_OFF_USER_ACTION));
        mHistorySyncButton.performClick();
        assertTrue(mActionTester.getActions().contains(CHANGE_HISTORY_SYNC_ON_USER_ACTION));
    }

    @Test
    @DisableFeatures({ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS})
    public void testStringsWhenReplaceSyncPromosWithSignInPromosFlagIsDisabled() throws Exception {
        initSyncState(true, true);
        mScenario =
                FragmentScenario.launchInContainer(
                        HistorySyncFragment.class, Bundle.EMPTY, R.style.Theme_MaterialComponents);
        mScenario.onFragment(
                fragment -> {
                    mHistorySyncButton = fragment.getView().findViewById(R.id.history_sync_switch);
                    assertEquals(
                            ((TextView) mHistorySyncButton.findViewById(R.id.switch_text))
                                    .getText(),
                            fragment.getContext()
                                    .getString(R.string.privacy_guide_history_sync_toggle));
                    assertEquals(
                            ((PrivacyGuideExplanationItem)
                                            fragment.getView()
                                                    .findViewById(R.id.history_sync_item_one))
                                    .getSummaryTextForTesting(),
                            fragment.getContext()
                                    .getString(R.string.privacy_guide_history_sync_item_one));
                });
    }

    @Test
    public void testStrings() throws Exception {
        initSyncState(true, true);
        mScenario =
                FragmentScenario.launchInContainer(
                        HistorySyncFragment.class, Bundle.EMPTY, R.style.Theme_MaterialComponents);
        mScenario.onFragment(
                fragment -> {
                    mHistorySyncButton = fragment.getView().findViewById(R.id.history_sync_switch);
                    assertEquals(
                            ((TextView) mHistorySyncButton.findViewById(R.id.switch_text))
                                    .getText(),
                            fragment.getContext()
                                    .getString(
                                            R.string.privacy_guide_history_and_tabs_sync_toggle));
                    assertEquals(
                            ((PrivacyGuideExplanationItem)
                                            fragment.getView()
                                                    .findViewById(R.id.history_sync_item_one))
                                    .getSummaryTextForTesting(),
                            fragment.getContext()
                                    .getString(
                                            R.string.privacy_guide_history_and_tabs_sync_item_one));
                });
    }

    @Test
    public void testToggleAccountsForTabsSync() throws Exception {
        Set<Integer> syncTypes = new HashSet<>();
        syncTypes.add(UserSelectableType.TABS);
        when(mSyncService.getSelectedTypes()).thenReturn(syncTypes);
        mScenario =
                FragmentScenario.launchInContainer(
                        HistorySyncFragment.class, Bundle.EMPTY, R.style.Theme_MaterialComponents);
        mScenario.onFragment(
                fragment -> {
                    mHistorySyncButton = fragment.getView().findViewById(R.id.history_sync_switch);
                    assertTrue(mHistorySyncButton.isChecked());
                });
    }
}