chromium/ui/android/junit/src/org/chromium/ui/AsyncViewProviderTest.java

// Copyright 2018 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.ui;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.ui.shadows.ShadowAsyncLayoutInflater;

import java.util.concurrent.atomic.AtomicInteger;

/** Tests logic in the AsyncViewProvider class. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(
        manifest = Config.NONE,
        shadows = {ShadowAsyncLayoutInflater.class})
public class AsyncViewProviderTest {
    private LinearLayout mRoot;
    private AsyncViewStub mAsyncViewStub;
    private AsyncViewProvider<View> mAsyncViewProvider;
    private final AtomicInteger mEventCount = new AtomicInteger();
    private static final int MAIN_LAYOUT_RESOURCE_ID = R.layout.main_view;
    private static final int INFLATE_LAYOUT_RESOURCE_ID = R.layout.inflated_view;
    private static final int STUB_ID = R.id.view_stub;
    private static final int INFLATED_VIEW_ID = R.id.inflated_view;
    private static final int PREINFLATED_VIEW_ID = R.id.pre_inflated_view;

    @Before
    public void setUp() {
        mRoot =
                (LinearLayout)
                        LayoutInflater.from(RuntimeEnvironment.application)
                                .inflate(MAIN_LAYOUT_RESOURCE_ID, null);
        mAsyncViewStub = mRoot.findViewById(STUB_ID);
        mAsyncViewStub.setLayoutResource(INFLATE_LAYOUT_RESOURCE_ID);
        mAsyncViewStub.setShouldInflateOnBackgroundThread(true);
        mAsyncViewProvider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
        mAsyncViewStub.setId(STUB_ID);
        mEventCount.set(0);
    }

    @Test
    public void testCreatesUnloadedProviderIfNotInflated() {
        AsyncViewProvider provider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
        assertNull(provider.get());
    }

    @Test
    public void testCreatesLoadedProviderIfInflated() {
        mAsyncViewStub.inflate();
        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
        AsyncViewProvider provider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
        assertNotNull(provider.get());
    }

    @Test
    public void testCreatesUnloadedProviderUsingResourceIds() {
        AsyncViewProvider provider = AsyncViewProvider.of(mRoot, STUB_ID, INFLATED_VIEW_ID);
        assertNull(provider.get());
    }

    @Test
    public void testCreatesLoadedProviderUsingResourceIds() {
        mAsyncViewStub.inflate();
        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
        AsyncViewProvider provider = AsyncViewProvider.of(mRoot, STUB_ID, INFLATED_VIEW_ID);
        assertNotNull(provider.get());
    }

    @Test
    public void testCreatesLoadedProviderUsingResourceIdsWithoutAsyncViewStub() {
        AsyncViewProvider provider = AsyncViewProvider.of(mRoot, 0, PREINFLATED_VIEW_ID);
        assertNotNull(provider.get());
        assertTrue(provider.get() instanceof ImageView);
    }

    @Test
    public void testRunsCallbackImmediatelyIfLoaded() {
        mAsyncViewStub.inflate();
        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
        AsyncViewProvider<View> provider = AsyncViewProvider.of(mAsyncViewStub, INFLATED_VIEW_ID);
        assertEquals(mEventCount.get(), 0);
        provider.whenLoaded(
                (View v) -> {
                    mEventCount.incrementAndGet();
                });
        assertEquals(mEventCount.get(), 1);
        provider.whenLoaded(
                (View v) -> {
                    mEventCount.incrementAndGet();
                });
        assertEquals(mEventCount.get(), 2);
    }

    @Test
    public void testCallsListenersOnUiThread() {
        mAsyncViewProvider.whenLoaded(
                (View v) -> {
                    assertTrue(ThreadUtils.runningOnUiThread());
                    mEventCount.incrementAndGet();
                });
        mAsyncViewStub.inflate();
        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
        // ensure callback gets called.
        assertEquals(mEventCount.get(), 1);
    }

    @Test
    public void testCallsListenersInOrder() {
        mAsyncViewProvider.whenLoaded(
                (View v) -> {
                    assertEquals(mEventCount.incrementAndGet(), 1);
                });
        mAsyncViewProvider.whenLoaded(
                (View v) -> {
                    assertEquals(mEventCount.incrementAndGet(), 2);
                });
        mAsyncViewProvider.whenLoaded(
                (View v) -> {
                    assertEquals(mEventCount.decrementAndGet(), 1);
                });
        assertEquals(mEventCount.get(), 0);
        mAsyncViewStub.inflate();
        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
        assertEquals(mEventCount.get(), 1);
    }
}