1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package androidx.emoji.widget; 17 18 import static androidx.emoji.util.EmojiMatcher.hasEmoji; 19 20 import static org.hamcrest.MatcherAssert.assertThat; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Matchers.anyInt; 24 import static org.mockito.Mockito.doReturn; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.spy; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.content.Context; 33 import android.os.Build; 34 import android.support.test.InstrumentationRegistry; 35 import android.support.test.filters.SdkSuppress; 36 import android.support.test.filters.SmallTest; 37 import android.support.test.runner.AndroidJUnit4; 38 import android.text.Editable; 39 import android.text.Selection; 40 import android.text.SpannableStringBuilder; 41 import android.view.inputmethod.EditorInfo; 42 import android.view.inputmethod.InputConnection; 43 import android.widget.TextView; 44 45 import androidx.emoji.text.EmojiCompat; 46 import androidx.emoji.text.TestConfigBuilder; 47 import androidx.emoji.util.Emoji; 48 import androidx.emoji.util.TestString; 49 50 import org.junit.Before; 51 import org.junit.BeforeClass; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 55 @SmallTest 56 @RunWith(AndroidJUnit4.class) 57 @SdkSuppress(minSdkVersion = 19) 58 public class EmojiInputConnectionTest { 59 60 private InputConnection mInputConnection; 61 private TestString mTestString; 62 private Editable mEditable; 63 private EmojiInputConnection mEmojiEmojiInputConnection; 64 65 @BeforeClass 66 public static void setupEmojiCompat() { 67 EmojiCompat.reset(TestConfigBuilder.config()); 68 } 69 70 @Before 71 public void setup() { 72 mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix(); 73 mEditable = new SpannableStringBuilder(mTestString.toString()); 74 mInputConnection = mock(InputConnection.class); 75 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 76 final TextView textView = spy(new TextView(context)); 77 EmojiCompat.get().process(mEditable); 78 assertThat(mEditable, hasEmoji()); 79 80 doReturn(mEditable).when(textView).getEditableText(); 81 when(mInputConnection.deleteSurroundingText(anyInt(), anyInt())).thenReturn(false); 82 setupDeleteSurroundingText(); 83 84 mEmojiEmojiInputConnection = new EmojiInputConnection(textView, mInputConnection, 85 new EditorInfo()); 86 } 87 88 private void setupDeleteSurroundingText() { 89 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 90 when(mInputConnection.deleteSurroundingTextInCodePoints(anyInt(), anyInt())).thenReturn( 91 false); 92 } 93 } 94 95 @Test 96 public void testDeleteSurroundingText_doesNotDelete() { 97 Selection.setSelection(mEditable, 0, mEditable.length()); 98 assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0)); 99 verify(mInputConnection, times(1)).deleteSurroundingText(1, 0); 100 } 101 102 @Test 103 public void testDeleteSurroundingText_deletesEmojiBackward() { 104 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 105 assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0)); 106 verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt()); 107 } 108 109 @Test 110 public void testDeleteSurroundingText_doesNotDeleteEmojiIfSelectionAtStartIndex() { 111 Selection.setSelection(mEditable, mTestString.emojiStartIndex()); 112 assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0)); 113 verify(mInputConnection, times(1)).deleteSurroundingText(1, 0); 114 } 115 116 @Test 117 public void testDeleteSurroundingText_deletesEmojiForward() { 118 Selection.setSelection(mEditable, mTestString.emojiStartIndex()); 119 assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(0, 1)); 120 verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt()); 121 } 122 123 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 124 @Test 125 public void testDeleteSurroundingTextInCodePoints_doesNotDelete() { 126 Selection.setSelection(mEditable, 0, mEditable.length()); 127 assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0)); 128 verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0); 129 } 130 131 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 132 @Test 133 public void testDeleteSurroundingTextInCodePoints_deletesEmojiBackward() { 134 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 135 assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0)); 136 verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt()); 137 } 138 139 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 140 @Test 141 public void testDeleteSurroundingTextInCodePoints_deletesEmojiForward() { 142 Selection.setSelection(mEditable, mTestString.emojiStartIndex()); 143 assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(0, 1)); 144 verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt()); 145 } 146 147 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 148 @Test 149 public void testDeleteSurroundingTextInCodePoints_doesNotDeleteEmojiIfSelectionAtStartIndex() { 150 Selection.setSelection(mEditable, mTestString.emojiStartIndex()); 151 assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0)); 152 verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0); 153 } 154 } 155