chromium/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkMoveSnackbarManagerTest.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.bookmarks;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking;

import android.app.Activity;

import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.annotation.Config;

import org.chromium.base.ActivityState;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.chrome.browser.app.bookmarks.BookmarkFolderPickerActivity;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.components.bookmarks.BookmarkId;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.ui.base.TestActivity;
import org.chromium.url.GURL;

import java.util.Arrays;

@Batch(Batch.UNIT_TESTS)
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
/** Unit tests for {@link BookmarkMoveSnackbarManager}. */
public class BookmarkMoveSnackbarManagerTest {
    @Rule
    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
            new ActivityScenarioRule<>(TestActivity.class);

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

    @Mock private SnackbarManager mSnackbarManager;
    @Mock private IdentityManager mIdentityManager;
    @Mock private BookmarkFolderPickerActivity mFolderPickerActivity;

    private BookmarkMoveSnackbarManager mBookmarkMoveSnackbarManager;
    private Activity mActivity;
    private FakeBookmarkModel mBookmarkModel;
    private BookmarkId mBookmarkId1;
    private BookmarkId mBookmarkId2;
    private BookmarkId mBookmarkId3;
    private BookmarkId mLongTextFolderId;
    private BookmarkId mMobileFolderId;
    private BookmarkId mAccountMobileFolderId;
    private BookmarkModelObserver mBookmarkModelObserver;
    private CoreAccountInfo mAccountInfo =
            CoreAccountInfo.createFromEmailAndGaiaId("[email protected]", "testGaiaId");

    @Before
    public void setUp() {
        mBookmarkModel = setupFakeBookmarkModel();
        mBookmarkModel.setAreAccountBookmarkFoldersActive(true);
        doReturn(mAccountInfo).when(mIdentityManager).getPrimaryAccountInfo(anyInt());
        doReturn(true).when(mSnackbarManager).canShowSnackbar();

        mActivityScenarioRule.getScenario().onActivity(this::onActivity);
    }

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

        mBookmarkMoveSnackbarManager =
                new BookmarkMoveSnackbarManager(
                        mActivity, mBookmarkModel, mSnackbarManager, mIdentityManager);
        mBookmarkModelObserver = mBookmarkMoveSnackbarManager.getBookmarkModelObserverForTesting();
    }

    private FakeBookmarkModel setupFakeBookmarkModel() {
        FakeBookmarkModel bookmarkModel = FakeBookmarkModel.createModel();
        mAccountMobileFolderId =
                runOnUiThreadBlocking(() -> bookmarkModel.getAccountMobileFolderId());
        mMobileFolderId = runOnUiThreadBlocking(() -> bookmarkModel.getMobileFolderId());
        mBookmarkId1 =
                runOnUiThreadBlocking(
                        () ->
                                bookmarkModel.addBookmark(
                                        mMobileFolderId, 0, "bookmark 1", new GURL("test1.com")));
        mBookmarkId2 =
                runOnUiThreadBlocking(
                        () ->
                                bookmarkModel.addBookmark(
                                        mMobileFolderId, 0, "bookmark 2", new GURL("test2.com")));
        mBookmarkId3 =
                runOnUiThreadBlocking(
                        () ->
                                bookmarkModel.addBookmark(
                                        mMobileFolderId, 0, "bookmark 3", new GURL("test3.com")));
        mLongTextFolderId =
                runOnUiThreadBlocking(
                        () ->
                                bookmarkModel.addFolder(
                                        mMobileFolderId,
                                        0,
                                        "Very long folder title which gets cut off at some point"));

        return bookmarkModel;
    }

    @Test
    @SmallTest
    public void testWithoutAnyMovement() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(mBookmarkId1);
        verifyNoInteractions(mSnackbarManager);

        mBookmarkMoveSnackbarManager.onActivityStateChange(
                mFolderPickerActivity, ActivityState.DESTROYED);
        verifyNoInteractions(mSnackbarManager);

        // Subsequent move events shouldn't be captured.
        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);
        verifyNoInteractions(mSnackbarManager);
    }

    @Test
    @SmallTest
    public void testSingleLocalMovement() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(mBookmarkId1);

        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);

        ArgumentCaptor<Snackbar> mSnackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
        verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture());
        Snackbar snackbar = mSnackbarCaptor.getValue();
        assertEquals(
                "Bookmark saved to \"Mobile bookmarks\". It is only saved to this device.",
                snackbar.getTextForTesting());
    }

    @Test
    @SmallTest
    public void testSingleAccountMovement() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(mBookmarkId1);

        mBookmarkModel.moveBookmark(mBookmarkId1, mAccountMobileFolderId, 0);
        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);

        ArgumentCaptor<Snackbar> mSnackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
        verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture());
        Snackbar snackbar = mSnackbarCaptor.getValue();
        assertEquals(
                "Bookmark saved to \"Mobile bookmarks\" in your account, [email protected].",
                snackbar.getTextForTesting());
    }

    @Test
    @SmallTest
    public void testMultipleLocalMovement() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(
                mBookmarkId1, mBookmarkId2, mBookmarkId3);

        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);

        ArgumentCaptor<Snackbar> mSnackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
        verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture());
        Snackbar snackbar = mSnackbarCaptor.getValue();
        assertEquals(
                "Bookmarks saved to \"Mobile bookmarks\". It is only saved to this device.",
                snackbar.getTextForTesting());
    }

    @Test
    @SmallTest
    public void testMultipleAccountMovement() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(
                mBookmarkId1, mBookmarkId2, mBookmarkId3);

        mBookmarkModel.moveBookmarks(
                Arrays.asList(mBookmarkId1, mBookmarkId2, mBookmarkId3), mAccountMobileFolderId);
        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);

        ArgumentCaptor<Snackbar> mSnackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
        verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture());
        Snackbar snackbar = mSnackbarCaptor.getValue();
        assertEquals(
                "Bookmarks saved to \"Mobile bookmarks\" in your account, [email protected].",
                snackbar.getTextForTesting());
    }

    @Test
    @SmallTest
    public void testMovementWithoutFeatureFlag() {
        mBookmarkModel.setAreAccountBookmarkFoldersActive(false);
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(mBookmarkId1);

        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);
        verifyNoInteractions(mSnackbarManager);
    }

    @Test
    @SmallTest
    public void testSnackbarAvailability() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(mBookmarkId1);

        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mMobileFolderId),
                0);
        doReturn(false).when(mSnackbarManager).canShowSnackbar();
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);
        verify(mSnackbarManager, times(0)).showSnackbar(any());
        doReturn(true).when(mSnackbarManager).canShowSnackbar();
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);

        ArgumentCaptor<Snackbar> mSnackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
        verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture());
        Snackbar snackbar = mSnackbarCaptor.getValue();
        assertEquals(
                "Bookmark saved to \"Mobile bookmarks\". It is only saved to this device.",
                snackbar.getTextForTesting());
    }

    @Test
    @SmallTest
    public void testMovementToFolderWithALongName() {
        mBookmarkMoveSnackbarManager.startFolderPickerAndObserveResult(mBookmarkId1);

        mBookmarkModelObserver.bookmarkNodeMoved(
                mBookmarkModel.getBookmarkById(mAccountMobileFolderId),
                0,
                mBookmarkModel.getBookmarkById(mLongTextFolderId),
                0);
        mBookmarkMoveSnackbarManager.onActivityStateChange(mActivity, ActivityState.RESUMED);

        ArgumentCaptor<Snackbar> mSnackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
        verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture());
        Snackbar snackbar = mSnackbarCaptor.getValue();
        assertEquals(
                "Bookmark saved to \"Very long folder title which get...\". It is only saved to"
                        + " this device.",
                snackbar.getTextForTesting());
    }
}