chromium/chrome/browser/search_engines/android/junit/src/org/chromium/chrome/browser/search_engines/choice_screen/ChoiceDialogCoordinatorUnitTest.java

// Copyright 2023 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.search_engines.choice_screen;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;

import android.os.Looper;

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.mockito.quality.Strictness;

import org.chromium.base.Promise;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.components.search_engines.SearchEngineChoiceService;
import org.chromium.components.search_engines.SearchEnginesFeatures;

@RunWith(BaseRobolectricTestRunner.class)
@Features.EnableFeatures({
    ChromeFeatureList.SEARCH_ENGINE_CHOICE,
    SearchEnginesFeatures.CLAY_BLOCKING
})
public class ChoiceDialogCoordinatorUnitTest {
    public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

    private @Mock ChoiceDialogCoordinator mDialogCoordinator;
    private @Mock SearchEngineChoiceService mSearchEngineChoiceService;

    @Before
    public void setUp() {
        SearchEngineChoiceService.setInstanceForTests(mSearchEngineChoiceService);
    }

    @Test
    public void testShouldShowDeviceChoiceDialog() {
        doReturn(true).when(mSearchEngineChoiceService).isDeviceChoiceDialogEligible();
        doReturn(Promise.fulfilled(true))
                .when(mSearchEngineChoiceService)
                .shouldShowDeviceChoiceDialog();

        assertNotNull(ChoiceDialogCoordinator.maybeShowInternal(() -> mDialogCoordinator));
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator).show();
    }

    @Test
    @Features.EnableFeatures({SearchEnginesFeatures.CLAY_BLOCKING})
    public void testShouldShowDeviceChoiceDialog_doesNotShowWhenNotEligible() {
        doReturn(false).when(mSearchEngineChoiceService).isDeviceChoiceDialogEligible();

        assertNull(ChoiceDialogCoordinator.maybeShowInternal(() -> mDialogCoordinator));
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator, never()).show();
    }

    @Test
    public void testShouldShowDeviceChoiceDialog_doesNotShowWhenShouldNot() {
        doReturn(true).when(mSearchEngineChoiceService).isDeviceChoiceDialogEligible();
        doReturn(Promise.fulfilled(false))
                .when(mSearchEngineChoiceService)
                .shouldShowDeviceChoiceDialog();

        assertNotNull(ChoiceDialogCoordinator.maybeShowInternal(() -> mDialogCoordinator));
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator, never()).show();
    }

    @Test
    public void testShouldShowDeviceChoiceDialog_showsAfterDelayedApproval() {
        var pendingPromise = new Promise<Boolean>();
        doReturn(true).when(mSearchEngineChoiceService).isDeviceChoiceDialogEligible();
        doReturn(pendingPromise).when(mSearchEngineChoiceService).shouldShowDeviceChoiceDialog();

        assertNotNull(ChoiceDialogCoordinator.maybeShowInternal(() -> mDialogCoordinator));
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator, never()).show();

        pendingPromise.fulfill(true);
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator).show();
    }

    @Test
    public void testShouldShowDeviceChoiceDialog_doesNotShowAfterDelayedDisapproval() {
        var pendingPromise = new Promise<Boolean>();
        doReturn(true).when(mSearchEngineChoiceService).isDeviceChoiceDialogEligible();
        doReturn(pendingPromise).when(mSearchEngineChoiceService).shouldShowDeviceChoiceDialog();

        assertNotNull(ChoiceDialogCoordinator.maybeShowInternal(() -> mDialogCoordinator));
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator, never()).show();

        pendingPromise.fulfill(false);
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator, never()).show();
    }

    @Test
    public void testShouldShowDeviceChoiceDialog_doesNotShowAfterTimeout() {
        var pendingPromise = new Promise<Boolean>();
        doReturn(true).when(mSearchEngineChoiceService).isDeviceChoiceDialogEligible();
        doReturn(pendingPromise).when(mSearchEngineChoiceService).shouldShowDeviceChoiceDialog();

        assertNotNull(ChoiceDialogCoordinator.maybeShowInternal(() -> mDialogCoordinator));
        shadowOf(Looper.getMainLooper()).idle();
        verify(mDialogCoordinator, never()).show();

        shadowOf(Looper.getMainLooper()).runToEndOfTasks(); // Advance past the timeout delay.
        verify(mDialogCoordinator, never()).show();
    }
}