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

// Copyright 2019 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.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.res.Resources;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.chromium.base.supplier.Supplier;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tasks.tab_management.PriceMessageService.PriceMessageType;
import org.chromium.chrome.tab_ui.R;
import org.chromium.ui.modelutil.PropertyModel;

import java.util.List;

/** Unit tests for {@link MessageCardProviderMediator}. */
@RunWith(BaseRobolectricTestRunner.class)
public class MessageCardProviderMediatorUnitTest {
    private static final int SUGGESTED_TAB_COUNT = 2;
    private static final int TESTING_ACTION = -1;

    private MessageCardProviderMediator mMediator;

    @Mock private MessageCardView.DismissActionProvider mUiDismissActionProvider;

    @Mock private Context mContext;

    @Mock private Resources mResourcesMock;

    @Mock private Profile mProfileMock;
    @Mock private Profile mIncognitoProfileMock;

    @Mock private PriceMessageService.PriceMessageData mPriceMessageData;

    @Mock private Supplier<Profile> mProfileSupplier;

    @Mock private IphMessageService.IphMessageData mIphMessageData;

    @Mock
    private IncognitoReauthPromoMessageService.IncognitoReauthMessageData
            mIncognitoReauthMessageData;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        doReturn(true).when(mIncognitoProfileMock).isOffTheRecord();
        doReturn(mProfileMock).when(mProfileSupplier).get();
        doNothing().when(mUiDismissActionProvider).dismiss(anyInt());
        mMediator =
                new MessageCardProviderMediator(
                        mContext, mProfileSupplier, mUiDismissActionProvider);
    }

    private void enqueueMessageItem(@MessageService.MessageType int type, int tabSuggestionAction) {
        switch (type) {
            case MessageService.MessageType.PRICE_MESSAGE:
                when(mPriceMessageData.getPriceDrop()).thenReturn(null);
                when(mPriceMessageData.getDismissActionProvider()).thenReturn((messageType) -> {});
                when(mPriceMessageData.getReviewActionProvider()).thenReturn(() -> {});
                when(mPriceMessageData.getType()).thenReturn(PriceMessageType.PRICE_WELCOME);
                mMediator.messageReady(type, mPriceMessageData);
                break;
            case MessageService.MessageType.IPH:
                when(mIphMessageData.getDismissActionProvider()).thenReturn((messageType) -> {});
                when(mIphMessageData.getReviewActionProvider()).thenReturn(() -> {});
                mMediator.messageReady(type, mIphMessageData);
                break;
            case MessageService.MessageType.INCOGNITO_REAUTH_PROMO_MESSAGE:
                when(mIncognitoReauthMessageData.getReviewActionProvider()).thenReturn(() -> {});
                mMediator.messageReady(type, mIncognitoReauthMessageData);
                break;
            default:
                mMediator.messageReady(type, new MessageService.MessageData() {});
        }
    }

    @Test
    public void getMessageItemsTest() {
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        Assert.assertEquals(1, mMediator.getMessageItems().size());
        Assert.assertTrue(mMediator.getReadyMessageItemsForTesting().isEmpty());
        Assert.assertFalse(mMediator.getShownMessageItemsForTesting().isEmpty());
    }

    @Test
    public void getMessageItemsTest_TwoDifferentTypeMessage() {
        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);

        Assert.assertEquals(1, mMediator.getMessageItems().size());
        Assert.assertTrue(mMediator.getReadyMessageItemsForTesting().isEmpty());
        Assert.assertFalse(mMediator.getShownMessageItemsForTesting().isEmpty());

        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        Assert.assertEquals(2, mMediator.getMessageItems().size());
        Assert.assertTrue(mMediator.getReadyMessageItemsForTesting().isEmpty());
        Assert.assertFalse(mMediator.getShownMessageItemsForTesting().isEmpty());
    }

    @Test
    public void getMessageItemsTest_OneMessageForEachMessageType() {
        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        List<MessageCardProviderMediator.Message> messages = mMediator.getMessageItems();
        Assert.assertEquals(2, messages.size());
        Assert.assertEquals(MessageService.MessageType.PRICE_MESSAGE, messages.get(0).type);
        Assert.assertEquals(MessageService.MessageType.FOR_TESTING, messages.get(1).type);

        Assert.assertEquals(2, mMediator.getShownMessageItemsForTesting().size());
        Assert.assertTrue(
                mMediator
                        .getShownMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.PRICE_MESSAGE));
        Assert.assertTrue(
                mMediator
                        .getShownMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.FOR_TESTING));
    }

    @Test
    public void getMessageItemsTest_ReturnFirstMessageFromMultipleSameTypeMessages() {
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        List<MessageCardProviderMediator.Message> messages =
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.FOR_TESTING);
        Assert.assertEquals(2, messages.size());
        final MessageCardProviderMediator.Message testingMessage1 = messages.get(0);
        final MessageCardProviderMediator.Message testingMessage2 = messages.get(1);

        messages = mMediator.getMessageItems();
        Assert.assertEquals(1, messages.size());
        Assert.assertEquals(testingMessage1, messages.get(0));

        Assert.assertEquals(1, mMediator.getShownMessageItemsForTesting().size());
        Assert.assertEquals(
                testingMessage1,
                mMediator
                        .getShownMessageItemsForTesting()
                        .get(MessageService.MessageType.FOR_TESTING));

        Assert.assertEquals(1, mMediator.getShownMessageItemsForTesting().size());
        Assert.assertEquals(
                testingMessage2,
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.FOR_TESTING)
                        .get(0));
    }

    @Test
    public void getMessageItemsTest_PersistUntilInvalidationOccurred() {
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        List<MessageCardProviderMediator.Message> messages =
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.FOR_TESTING);
        Assert.assertEquals(2, messages.size());
        final MessageCardProviderMediator.Message testingMessage1 = messages.get(0);

        // Test message is persisted.
        for (int i = 0; i < 2; i++) {
            messages = mMediator.getMessageItems();
            Assert.assertEquals(1, messages.size());
            Assert.assertEquals(testingMessage1, messages.get(0));
        }

        // Test message updated after invalidation, and the updated message is persisted.
        mMediator.invalidateShownMessage(MessageService.MessageType.FOR_TESTING);
        messages = mMediator.getMessageItems();
        final MessageCardProviderMediator.Message newMessage = messages.get(0);
        Assert.assertEquals(1, messages.size());
        Assert.assertNotEquals(testingMessage1, newMessage);
        for (int i = 0; i < 2; i++) {
            messages = mMediator.getMessageItems();
            Assert.assertEquals(1, messages.size());
            Assert.assertEquals(newMessage, messages.get(0));
        }
    }

    @Test
    public void getMessageItemsTest_ReturnNextMessageIfShownMessageIsInvalided() {
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        List<MessageCardProviderMediator.Message> messages =
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.FOR_TESTING);
        Assert.assertEquals(2, messages.size());
        final MessageCardProviderMediator.Message testingMessage1 = messages.get(0);
        final MessageCardProviderMediator.Message testingMessage2 = messages.get(1);

        messages = mMediator.getMessageItems();
        Assert.assertEquals(1, messages.size());
        Assert.assertEquals(testingMessage1, messages.get(0));

        mMediator.invalidateShownMessage(MessageService.MessageType.FOR_TESTING);

        messages = mMediator.getMessageItems();
        Assert.assertEquals(1, messages.size());
        Assert.assertEquals(testingMessage2, messages.get(0));

        mMediator.invalidateShownMessage(MessageService.MessageType.FOR_TESTING);
        Assert.assertEquals(0, mMediator.getMessageItems().size());
    }

    @Test
    public void invalidate_allMessages() {
        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);

        mMediator.messageInvalidate(MessageService.MessageType.PRICE_MESSAGE);

        Assert.assertFalse(
                mMediator
                        .getReadyMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.PRICE_MESSAGE));
        Assert.assertFalse(
                mMediator
                        .getShownMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.PRICE_MESSAGE));

        // Testing multiple Messages has the same type.
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        mMediator.messageInvalidate(MessageService.MessageType.FOR_TESTING);
        Assert.assertFalse(
                mMediator
                        .getReadyMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.FOR_TESTING));
        Assert.assertFalse(
                mMediator
                        .getShownMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.FOR_TESTING));
    }

    @Test
    public void invalidate_shownMessage() {
        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);

        mMediator.getMessageItems();
        mMediator.invalidateShownMessage(MessageService.MessageType.PRICE_MESSAGE);

        verify(mUiDismissActionProvider).dismiss(anyInt());
        Assert.assertFalse(
                mMediator
                        .getShownMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.PRICE_MESSAGE));
        Assert.assertFalse(
                mMediator
                        .getReadyMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.PRICE_MESSAGE));

        // Testing multiple Messages has the same type.
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);
        enqueueMessageItem(MessageService.MessageType.FOR_TESTING, TESTING_ACTION);

        mMediator.getMessageItems();
        mMediator.invalidateShownMessage(MessageService.MessageType.FOR_TESTING);
        Assert.assertFalse(
                mMediator
                        .getShownMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.FOR_TESTING));
        Assert.assertTrue(
                mMediator
                        .getReadyMessageItemsForTesting()
                        .containsKey(MessageService.MessageType.FOR_TESTING));
    }

    @Test
    public void buildModel_ForPriceMessage() {
        String titleText = "Price drop spotted";
        doReturn(titleText).when(mContext).getString(R.string.price_drop_spotted_title);

        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);

        PropertyModel model =
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.PRICE_MESSAGE)
                        .get(0)
                        .model;
        Assert.assertEquals(
                MessageService.MessageType.PRICE_MESSAGE,
                model.get(MessageCardViewProperties.MESSAGE_TYPE));
        Assert.assertEquals(titleText, model.get(MessageCardViewProperties.TITLE_TEXT));
    }

    @Test
    public void buildModel_ForIphMessage() {
        enqueueMessageItem(MessageService.MessageType.IPH, -1);

        PropertyModel model =
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.IPH)
                        .get(0)
                        .model;
        Assert.assertEquals(
                MessageService.MessageType.IPH, model.get(MessageCardViewProperties.MESSAGE_TYPE));
    }

    @Test
    public void buildModel_ForIncognitoReauthPromoMessage() {
        final int height = 1;
        final int width = 2;
        when(mResourcesMock.getDimensionPixelSize(
                        R.dimen.incognito_reauth_promo_message_icon_height))
                .thenReturn(height);
        when(mResourcesMock.getDimensionPixelSize(
                        R.dimen.incognito_reauth_promo_message_icon_width))
                .thenReturn(width);
        when(mContext.getResources()).thenReturn(mResourcesMock);

        enqueueMessageItem(MessageService.MessageType.INCOGNITO_REAUTH_PROMO_MESSAGE, -1);

        PropertyModel model =
                mMediator
                        .getReadyMessageItemsForTesting()
                        .get(MessageService.MessageType.INCOGNITO_REAUTH_PROMO_MESSAGE)
                        .get(0)
                        .model;
        Assert.assertEquals(
                MessageService.MessageType.INCOGNITO_REAUTH_PROMO_MESSAGE,
                model.get(MessageCardViewProperties.MESSAGE_TYPE));
        verify(mResourcesMock, times(1))
                .getDimensionPixelSize(R.dimen.incognito_reauth_promo_message_icon_height);
        verify(mResourcesMock, times(1))
                .getDimensionPixelSize(R.dimen.incognito_reauth_promo_message_icon_width);
        verify(mContext, times(2)).getResources();
    }

    @Test
    public void getMessageItemsTest_UpdateIncognito() {
        enqueueMessageItem(MessageService.MessageType.IPH, -1);

        PropertyModel messageModel = mMediator.getMessageItems().get(0).model;
        Assert.assertFalse(messageModel.get(MessageCardViewProperties.IS_INCOGNITO));

        doReturn(mIncognitoProfileMock).when(mProfileSupplier).get();
        messageModel = mMediator.getMessageItems().get(0).model;
        Assert.assertTrue(messageModel.get(MessageCardViewProperties.IS_INCOGNITO));
    }

    @Test
    public void getNextMessageItemForTypeTest_UpdateIncognito() {
        enqueueMessageItem(MessageService.MessageType.IPH, -1);

        PropertyModel messageModel =
                mMediator.getNextMessageItemForType(MessageService.MessageType.IPH).model;
        Assert.assertFalse(messageModel.get(MessageCardViewProperties.IS_INCOGNITO));

        doReturn(mIncognitoProfileMock).when(mProfileSupplier).get();
        messageModel = mMediator.getNextMessageItemForType(MessageService.MessageType.IPH).model;
        Assert.assertTrue(messageModel.get(MessageCardViewProperties.IS_INCOGNITO));
    }

    @Test
    public void isMessageShownTest() {
        Assert.assertFalse(
                mMediator.isMessageShown(
                        MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_WELCOME));
        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);
        // Mock pulling this message, which will move the message from mMessageItems to
        // mShownMessageItems.
        mMediator.getNextMessageItemForType(MessageService.MessageType.PRICE_MESSAGE);
        Assert.assertTrue(
                mMediator.isMessageShown(
                        MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_WELCOME));
        Assert.assertFalse(
                mMediator.isMessageShown(
                        MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_ALERTS));
    }
}