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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;

import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.CLICK_LISTENER;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.FAVICON;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.IS_VISIBLE;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.LATERAL_MARGIN;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.SEE_MORE_LINK_CLICK_LISTENER;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TAB_THUMBNAIL;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.TITLE;
import static org.chromium.chrome.browser.single_tab.SingleTabViewProperties.URL;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.test.filters.SmallTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.tab_ui.TabListFaviconProvider;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;

/** Tests for {@link SingleTabViewBinder} with {@link R.layout.single_tab_module_layout} */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class SingleTabModuleViewBinderUnitTest {
    private static final String TEST_TITLE = "test";
    private static final String TEST_URL = "www.foo.com";
    private final int mTabId = 1;
    private static final String HISTOGRAM_START_SURFACE_MODULE_CLICK = "StartSurface.Module.Click";

    private Activity mActivity;
    private SingleTabView mSingleTabModuleView;
    private PropertyModelChangeProcessor<PropertyModel, SingleTabView, PropertyKey>
            mPropertyModelChangeProcessor;
    private PropertyModel mPropertyModel;

    @Mock private View.OnClickListener mClickListener;
    @Mock private Runnable mSeeMoreLinkClickListener;
    @Mock private TabModelSelector mTabModelSelector;
    @Mock private TabListFaviconProvider mTabListFaviconProvider;

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

        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
        mSingleTabModuleView =
                (SingleTabView)
                        mActivity
                                .getLayoutInflater()
                                .inflate(R.layout.single_tab_module_layout, null);
        mActivity.setContentView(mSingleTabModuleView);

        mPropertyModel = new PropertyModel(SingleTabViewProperties.ALL_KEYS);
        mPropertyModelChangeProcessor =
                PropertyModelChangeProcessor.create(
                        mPropertyModel, mSingleTabModuleView, SingleTabViewBinder::bind);
    }

    @After
    public void tearDown() throws Exception {
        mPropertyModelChangeProcessor.destroy();
        mPropertyModel = null;
        mSingleTabModuleView = null;
        mActivity = null;
    }

    private boolean isViewVisible(int viewId) {
        return mSingleTabModuleView.findViewById(viewId).getVisibility() == View.VISIBLE;
    }

    @Test
    @SmallTest
    public void testVisibility() {
        mPropertyModel.set(IS_VISIBLE, true);
        assertTrue(isViewVisible(org.chromium.chrome.R.id.single_tab_view));

        mPropertyModel.set(IS_VISIBLE, false);
        assertFalse(isViewVisible(org.chromium.chrome.R.id.single_tab_view));
    }

    @Test
    @SmallTest
    public void testSetTitle() {
        TextView title = mSingleTabModuleView.findViewById(org.chromium.chrome.R.id.tab_title_view);
        assertEquals("", title.getText());

        mPropertyModel.set(TITLE, TEST_TITLE);
        assertEquals(TEST_TITLE, title.getText());
    }

    @Test
    @SmallTest
    public void testSetUrl() {
        TextView url = mSingleTabModuleView.findViewById(org.chromium.chrome.R.id.tab_url_view);
        assertEquals("", url.getText());

        mPropertyModel.set(URL, TEST_URL);
        assertEquals(TEST_URL, url.getText());
    }

    @Test
    @SmallTest
    public void testSetFavicon() {
        ImageView favicon =
                mSingleTabModuleView.findViewById(org.chromium.chrome.R.id.tab_favicon_view);
        assertNull(favicon.getDrawable());

        mPropertyModel.set(FAVICON, new BitmapDrawable());
        assertNotNull(favicon.getDrawable());
    }

    @Test
    @SmallTest
    public void testSetTabThumbnail() {
        // Fake a layout so the UI has a size.
        mSingleTabModuleView.measure(0, 0);
        mSingleTabModuleView.layout(0, 0, 100, 100);

        ImageView thumbnail = mSingleTabModuleView.findViewById(R.id.tab_thumbnail);

        Bitmap bitmap = Bitmap.createBitmap(300, 400, Bitmap.Config.ALPHA_8);
        mPropertyModel.set(TAB_THUMBNAIL, new BitmapDrawable(bitmap));
        assertNotNull(thumbnail.getDrawable());

        assertNotEquals(new Matrix(), thumbnail.getImageMatrix());
    }

    @Test
    @SmallTest
    public void testSetTabThumbnailUpdateMatrixOnResize() {
        ImageView thumbnail = mSingleTabModuleView.findViewById(R.id.tab_thumbnail);

        Bitmap bitmap = Bitmap.createBitmap(300, 400, Bitmap.Config.ALPHA_8);
        mPropertyModel.set(TAB_THUMBNAIL, new BitmapDrawable(bitmap));
        assertNotNull(thumbnail.getDrawable());

        Matrix identityMatrix = new Matrix();
        assertEquals(identityMatrix, thumbnail.getImageMatrix());

        // Fake a layout so the UI has a size.
        mSingleTabModuleView.measure(0, 0);
        mSingleTabModuleView.layout(0, 0, 100, 100);

        assertNotEquals(identityMatrix, thumbnail.getImageMatrix());
    }

    @Test
    @SmallTest
    public void testClickListener() {
        mPropertyModel.set(CLICK_LISTENER, mClickListener);
        mSingleTabModuleView.performClick();
        verify(mClickListener).onClick(any());

        mPropertyModel.set(SEE_MORE_LINK_CLICK_LISTENER, mSeeMoreLinkClickListener);
        TextView seeMoreLinkView =
                mSingleTabModuleView.findViewById(R.id.tab_switcher_see_more_link);
        assertNotNull(seeMoreLinkView);
        seeMoreLinkView.performClick();
        verify(mSeeMoreLinkClickListener).run();
    }

    @Test
    @SmallTest
    public void testStartMargin() {
        int lateralMargin = 100;
        MarginLayoutParams marginLayoutParams =
                (MarginLayoutParams) mSingleTabModuleView.getLayoutParams();
        assertEquals(0, marginLayoutParams.getMarginStart());

        mPropertyModel.set(LATERAL_MARGIN, lateralMargin);
        assertEquals(100, marginLayoutParams.getMarginStart());
    }
}