chromium/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java

// Copyright 2017 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.content.browser.androidoverlay;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.content.Context;

import androidx.test.filters.SmallTest;

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.androidoverlay.DialogOverlayImplTestRule.Client;
import org.chromium.ui.base.ImmutableWeakReference;
import org.chromium.ui.base.WindowAndroid;

/** Tests for DialogOverlayImpl. */
@RunWith(BaseJUnit4ClassRunner.class)
@DisabledTest(message = "https://crbug.com/1462304")
public class DialogOverlayImplTest {
    private static final String BLANK_URL = "about:blank";

    @Rule
    public DialogOverlayImplTestRule mActivityTestRule = new DialogOverlayImplTestRule(BLANK_URL);

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testCreateDestroyOverlay() {
        Assert.assertFalse(mActivityTestRule.getClient().hasReceivedOverlayModeChange());
        Assert.assertFalse(mActivityTestRule.getClient().isUsingOverlayMode());

        final DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);

        // We should get a new overlay with a valid surface key.
        Client.Event event = mActivityTestRule.getClient().nextEvent();
        Assert.assertEquals(Client.SURFACE_READY, event.which);
        Assert.assertTrue(event.surfaceKey > 0);

        Assert.assertTrue(mActivityTestRule.getClient().hasReceivedOverlayModeChange());
        Assert.assertTrue(mActivityTestRule.getClient().isUsingOverlayMode());

        // Close the overlay, and make sure that the provider is notified.
        // Note that we should not get a 'destroyed' message when we close it.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    overlay.close();
                });
        Assert.assertEquals(Client.RELEASED, mActivityTestRule.getClient().nextEvent().which);
        Assert.assertFalse(mActivityTestRule.getClient().isUsingOverlayMode());
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testCreateOverlayFailsIfUnknownRoutingToken() {
        // Try to create an overlay with a bad routing token.
        mActivityTestRule.incrementUnguessableTokenHigh();
        DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);
        Assert.assertNotNull(overlay);

        // We should be notified that the overlay is destroyed.
        Client.Event event = mActivityTestRule.getClient().nextEvent();
        Assert.assertEquals(Client.DESTROYED, event.which);
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testCreateOverlayFailsIfWebContentsHidden() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mActivityTestRule.getWebContents().onHide();
                });

        DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);
        Assert.assertNotNull(overlay);

        // We should be notified that the overlay is destroyed.
        Client.Event event = mActivityTestRule.getClient().nextEvent();
        Assert.assertEquals(Client.DESTROYED, event.which);
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testHiddingWebContentsDestroysOverlay() {
        DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);
        Assert.assertNotNull(overlay);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mActivityTestRule.getWebContents().onHide();
                });

        // We should be notified that the overlay is destroyed.
        Client.Event event = mActivityTestRule.getClient().nextEvent();
        Assert.assertEquals(Client.DESTROYED, event.which);
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testScheduleLayoutDoesntCrash() {
        // Make sure that we don't get any messages due to scheduleLayout, and we don't crash.
        final DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);

        // Wait for the surface.
        Assert.assertEquals(Client.SURFACE_READY, mActivityTestRule.getClient().nextEvent().which);
        final org.chromium.gfx.mojom.Rect rect = new org.chromium.gfx.mojom.Rect();
        rect.x = 100;
        rect.y = 200;
        rect.width = 100;
        rect.height = 100;
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    overlay.scheduleLayout(rect);
                });

        // No additional messages should have arrived.
        Assert.assertTrue(mActivityTestRule.getClient().isEmpty());
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testCreateSecureSurface() {
        // Test that creating a secure overlay creates an overlay.  We can't really tell if it's
        // secure or not, until we can do a screen shot test.
        mActivityTestRule.setSecure(true);
        final DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);
        Assert.assertNotNull(overlay);

        // We should get a new overlay with a valid surface key.
        Client.Event event = mActivityTestRule.getClient().nextEvent();
        Assert.assertEquals(Client.SURFACE_READY, event.which);
        Assert.assertTrue(event.surfaceKey > 0);
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testCloseOnlyClosesOnce() {
        // Test that trying to close an overlay more than once doesn't actually do anything.
        final DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);
        // The first should generate RELEASED
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    overlay.close();
                });
        Assert.assertEquals(Client.RELEASED, mActivityTestRule.getClient().nextEvent().which);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    overlay.close();
                    mActivityTestRule.getClient().injectMarkerEvent();
                });
        Assert.assertEquals(Client.TEST_MARKER, mActivityTestRule.getClient().nextEvent().which);
    }

    @Test
    @SmallTest
    @Feature({"AndroidOverlay"})
    public void testEmptyWindowAndroidDoesntCrash() {
        // Test that receiving a WindowAndroid that doesn't have activity donesn't cause crash.
        ImmutableWeakReference<Context> nullContextWeakRef = new ImmutableWeakReference<>(null);
        WindowAndroid mockWindowAndroid = mock(WindowAndroid.class);
        when(mockWindowAndroid.getContext()).thenReturn(nullContextWeakRef);
        final DialogOverlayImpl overlay = mActivityTestRule.createOverlay(0, 0, 10, 10);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    overlay.onWindowAndroid(mockWindowAndroid);
                });
    }
}