| Index: content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| diff --git a/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b1f5e6d7b06d5985a63bbab4641e8fa2686178bd
|
| --- /dev/null
|
| +++ b/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
|
| @@ -0,0 +1,164 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// 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.input;
|
| +
|
| +import static org.junit.Assert.assertEquals;
|
| +import static org.junit.Assert.assertFalse;
|
| +import static org.junit.Assert.assertNull;
|
| +import static org.junit.Assert.assertTrue;
|
| +import static org.junit.Assert.fail;
|
| +import static org.mockito.Mockito.inOrder;
|
| +import static org.mockito.Mockito.never;
|
| +import static org.mockito.Mockito.when;
|
| +
|
| +import android.os.Handler;
|
| +
|
| +import org.chromium.base.ThreadUtils;
|
| +import org.chromium.base.test.util.Feature;
|
| +import org.chromium.content.browser.input.ChromiumBaseInputConnection.ThreadManager;
|
| +import org.chromium.testing.local.LocalRobolectricTestRunner;
|
| +import org.junit.Before;
|
| +import org.junit.Test;
|
| +import org.junit.runner.RunWith;
|
| +import org.mockito.InOrder;
|
| +import org.mockito.Mock;
|
| +import org.mockito.Mockito;
|
| +import org.mockito.MockitoAnnotations;
|
| +import org.robolectric.annotation.Config;
|
| +
|
| +/**
|
| + * Unit tests for {@ThreadedInputConnection}.
|
| + */
|
| +@RunWith(LocalRobolectricTestRunner.class)
|
| +@Config(manifest = Config.NONE)
|
| +public class ThreadedInputConnectionTest {
|
| +
|
| + @Mock ImeAdapter mImeAdapter;
|
| + ThreadManager mThreadManager;
|
| + ThreadedInputConnection mConnection;
|
| + InOrder mInOrder;
|
| +
|
| + @Before
|
| + public void setUp() throws Exception {
|
| + MockitoAnnotations.initMocks(this);
|
| +
|
| + mImeAdapter = Mockito.mock(ImeAdapter.class);
|
| + mInOrder = inOrder(mImeAdapter);
|
| + // Let's create ThreadManager for test thread and pretend that it is an IME thread.
|
| + mThreadManager = new ThreadManager(new Handler());
|
| + mConnection = new ThreadedInputConnection(mImeAdapter, mThreadManager);
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testComposeGetTextFinishGetText() {
|
| + // IME app calls setComposingText().
|
| + mConnection.setComposingText("hello", 1);
|
| + mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, false);
|
| +
|
| + // Renderer updates states asynchronously.
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, true);
|
| + mInOrder.verify(mImeAdapter).updateSelection(5, 5, 0, 5);
|
| + assertEquals(0, mConnection.getQueueForTest().size());
|
| +
|
| + // Prepare to call requestTextInputStateUpdate.
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, false);
|
| + assertEquals(1, mConnection.getQueueForTest().size());
|
| + when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
| +
|
| + // IME app calls getTextBeforeCursor().
|
| + assertEquals("hello", mConnection.getTextBeforeCursor(20, 0));
|
| +
|
| + // IME app calls finishComposingText().
|
| + mConnection.finishComposingText();
|
| + mInOrder.verify(mImeAdapter).finishComposingText();
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true);
|
| + mInOrder.verify(mImeAdapter).updateSelection(5, 5, -1, -1);
|
| +
|
| + // Prepare to call requestTextInputStateUpdate.
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false);
|
| + assertEquals(1, mConnection.getQueueForTest().size());
|
| + when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
| +
|
| + // IME app calls getTextBeforeCursor().
|
| + assertEquals("hello", mConnection.getTextBeforeCursor(20, 0));
|
| +
|
| + assertEquals(0, mConnection.getQueueForTest().size());
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testRenderChangeUpdatesSelection() {
|
| + // User moves the cursor.
|
| + mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, true);
|
| + mInOrder.verify(mImeAdapter).updateSelection(4, 4, -1, -1);
|
| + assertEquals(0, mConnection.getQueueForTest().size());
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testBatchEdit() {
|
| + // IME app calls beginBatchEdit().
|
| + assertTrue(mConnection.beginBatchEdit());
|
| + // Type hello real fast.
|
| + mConnection.commitText("hello", 1);
|
| + mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, true);
|
| +
|
| + // Renderer updates states asynchronously.
|
| + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true);
|
| + mInOrder.verify(mImeAdapter, never()).updateSelection(5, 5, -1, -1);
|
| + assertEquals(0, mConnection.getQueueForTest().size());
|
| +
|
| + {
|
| + // Nest another batch edit.
|
| + assertTrue(mConnection.beginBatchEdit());
|
| + // Move the cursor to the left.
|
| + mConnection.setSelection(4, 4);
|
| + assertTrue(mConnection.endBatchEdit());
|
| + }
|
| + // We still have one outer batch edit, so should not update selection yet.
|
| + mInOrder.verify(mImeAdapter, never()).updateSelection(4, 4, -1, -1);
|
| +
|
| + // Prepare to call requestTextInputStateUpdate.
|
| + mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, false);
|
| + assertEquals(1, mConnection.getQueueForTest().size());
|
| + when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
| +
|
| + // IME app calls endBatchEdit().
|
| + assertFalse(mConnection.endBatchEdit());
|
| + // Batch edit is finished, now update selection.
|
| + mInOrder.verify(mImeAdapter).updateSelection(4, 4, -1, -1);
|
| + assertEquals(0, mConnection.getQueueForTest().size());
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testFailToRequestToRenderer() {
|
| + when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(false);
|
| + // Should not hang here. Return null to indicate failure.
|
| + assertNull(null, mConnection.getTextBeforeCursor(10, 0));
|
| + }
|
| +
|
| + @Test
|
| + @Feature({"TextInput"})
|
| + public void testRendererCannotUpdateState() {
|
| + when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true);
|
| + // We found that renderer cannot update state, e.g., due to a crash.
|
| + ThreadUtils.postOnUiThread(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + try {
|
| + Thread.sleep(1000);
|
| + } catch (InterruptedException e) {
|
| + e.printStackTrace();
|
| + fail();
|
| + }
|
| + mConnection.unblockOnUiThread();
|
| + }
|
| + });
|
| + // Should not hang here. Return null to indicate failure.
|
| + assertEquals(null, mConnection.getTextBeforeCursor(10, 0));
|
| + }
|
| +}
|
|
|