1/* 2 * Copyright 2018 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 */ 16package androidx.emoji.text; 17 18import static androidx.emoji.util.Emoji.EMOJI_FLAG; 19import static androidx.emoji.util.Emoji.EMOJI_GENDER; 20import static androidx.emoji.util.Emoji.EMOJI_WITH_ZWJ; 21import static androidx.emoji.util.EmojiMatcher.hasEmoji; 22import static androidx.emoji.util.EmojiMatcher.hasEmojiCount; 23import static androidx.emoji.util.KeyboardUtil.altDel; 24import static androidx.emoji.util.KeyboardUtil.ctrlDel; 25import static androidx.emoji.util.KeyboardUtil.del; 26import static androidx.emoji.util.KeyboardUtil.fnDel; 27import static androidx.emoji.util.KeyboardUtil.forwardDel; 28import static androidx.emoji.util.KeyboardUtil.shiftDel; 29import static androidx.emoji.util.KeyboardUtil.zero; 30 31import static org.hamcrest.MatcherAssert.assertThat; 32import static org.hamcrest.core.IsNot.not; 33import static org.junit.Assert.assertEquals; 34import static org.junit.Assert.assertFalse; 35import static org.junit.Assert.assertTrue; 36 37import android.support.test.filters.SdkSuppress; 38import android.support.test.filters.SmallTest; 39import android.support.test.runner.AndroidJUnit4; 40import android.text.Editable; 41import android.text.Selection; 42import android.text.SpannableStringBuilder; 43import android.view.KeyEvent; 44 45import androidx.emoji.util.TestString; 46 47import org.junit.Before; 48import org.junit.BeforeClass; 49import org.junit.Test; 50import org.junit.runner.RunWith; 51 52@SmallTest 53@RunWith(AndroidJUnit4.class) 54@SdkSuppress(minSdkVersion = 19) 55public class HardDeleteTest { 56 57 private TestString mTestString; 58 private Editable mEditable; 59 60 @BeforeClass 61 public static void setupEmojiCompat() { 62 EmojiCompat.reset(TestConfigBuilder.config()); 63 } 64 65 @Before 66 public void setup() { 67 mTestString = new TestString(EMOJI_WITH_ZWJ).withPrefix().withSuffix(); 68 mEditable = new SpannableStringBuilder(mTestString.toString()); 69 EmojiCompat.get().process(mEditable); 70 assertThat(mEditable, hasEmojiCount(1)); 71 assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ)); 72 } 73 74 @Test 75 public void testOnKeyDown_doesNotDelete_whenKeyCodeIsNotDelOrForwardDel() { 76 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 77 final KeyEvent event = zero(); 78 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 79 assertThat(mEditable, hasEmoji()); 80 assertEquals(mTestString.toString(), mEditable.toString()); 81 } 82 83 @Test 84 public void testOnKeyDown_doesNotDelete_withOtherModifiers() { 85 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 86 final KeyEvent event = fnDel(); 87 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 88 assertThat(mEditable, hasEmoji()); 89 assertEquals(mTestString.toString(), mEditable.toString()); 90 } 91 92 @Test 93 public void testOnKeyDown_doesNotDelete_withAltModifier() { 94 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 95 final KeyEvent event = altDel(); 96 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 97 assertThat(mEditable, hasEmoji()); 98 assertEquals(mTestString.toString(), mEditable.toString()); 99 } 100 101 @Test 102 public void testOnKeyDown_doesNotDelete_withCtrlModifier() { 103 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 104 final KeyEvent event = ctrlDel(); 105 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 106 assertThat(mEditable, hasEmoji()); 107 assertEquals(mTestString.toString(), mEditable.toString()); 108 } 109 110 @Test 111 public void testOnKeyDown_doesNotDelete_withShiftModifier() { 112 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 113 final KeyEvent event = shiftDel(); 114 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 115 assertThat(mEditable, hasEmoji()); 116 assertEquals(mTestString.toString(), mEditable.toString()); 117 } 118 119 @Test 120 public void testOnKeyDown_doesNotDelete_withSelectionLongerThanZeroLength() { 121 // when there is a selection which is longer than 0, it should not delete. 122 Selection.setSelection(mEditable, 0, mEditable.length()); 123 final KeyEvent event = del(); 124 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 125 assertThat(mEditable, hasEmoji()); 126 assertEquals(mTestString.toString(), mEditable.toString()); 127 } 128 129 @Test 130 public void testOnKeyDown_doesNotDelete_withoutEmojiSpans() { 131 final Editable editable = new SpannableStringBuilder("abc"); 132 Selection.setSelection(editable, 1); 133 final KeyEvent event = del(); 134 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 135 assertThat(mEditable, hasEmoji()); 136 assertEquals(mTestString.toString(), mEditable.toString()); 137 } 138 139 @Test 140 public void testOnKeyDown_doesNotDelete_whenNoSpansBefore() { 141 Selection.setSelection(mEditable, mTestString.emojiStartIndex()); 142 final KeyEvent event = del(); 143 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 144 assertThat(mEditable, hasEmoji()); 145 assertEquals(mTestString.toString(), mEditable.toString()); 146 } 147 148 @Test 149 public void testOnKeyDown_deletesEmoji() { 150 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 151 final KeyEvent event = del(); 152 assertTrue(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 153 assertThat(mEditable, not(hasEmoji())); 154 assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString()); 155 } 156 157 @Test 158 public void testOnKeyDown_doesNotForwardDeleteEmoji_withNoSpansAfter() { 159 Selection.setSelection(mEditable, mTestString.emojiEndIndex()); 160 final KeyEvent event = forwardDel(); 161 assertFalse(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 162 assertThat(mEditable, hasEmoji()); 163 assertEquals(mTestString.toString(), mEditable.toString()); 164 } 165 166 @Test 167 public void testOnKeyDown_forwardDeletesEmoji() { 168 Selection.setSelection(mEditable, mTestString.emojiStartIndex()); 169 final KeyEvent event = forwardDel(); 170 assertTrue(EmojiCompat.handleOnKeyDown(mEditable, event.getKeyCode(), event)); 171 assertThat(mEditable, not(hasEmoji())); 172 assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString()); 173 } 174 175 @Test 176 public void testOnKeyDown_deletesEmoji_ifSelectionIsInSpanBoundaries() { 177 Selection.setSelection(mEditable, mTestString.emojiStartIndex() + 1); 178 final KeyEvent delEvent = del(); 179 assertTrue(EmojiCompat.handleOnKeyDown(mEditable, delEvent.getKeyCode(), delEvent)); 180 assertThat(mEditable, not(hasEmoji())); 181 assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString()); 182 } 183 184 @Test 185 public void testOnKeyDown_deletesEmoji_ifSelectionIsInSpanBoundaries_withForwardDel() { 186 Selection.setSelection(mEditable, mTestString.emojiStartIndex() + 1); 187 final KeyEvent forwardDelEvent = forwardDel(); 188 assertTrue(EmojiCompat.handleOnKeyDown(mEditable, forwardDelEvent.getKeyCode(), 189 forwardDelEvent)); 190 assertThat(mEditable, not(hasEmoji())); 191 assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString()); 192 } 193 194 @Test 195 public void testOnKeyDown_deletesOnlyEmojiBeforeTheCursor() { 196 // contains three emojis 197 mTestString = new TestString(EMOJI_FLAG) 198 .append(EMOJI_WITH_ZWJ) 199 .append(EMOJI_GENDER) 200 .withPrefix().withSuffix(); 201 mEditable = new SpannableStringBuilder(mTestString.toString()); 202 EmojiCompat.get().process(mEditable); 203 204 // put the cursor after the second emoji 205 Selection.setSelection(mEditable, mTestString.emojiStartIndex() 206 + EMOJI_FLAG.charCount() 207 + EMOJI_WITH_ZWJ.charCount()); 208 209 // delete 210 final KeyEvent forwardDelEvent = del(); 211 assertTrue(EmojiCompat.handleOnKeyDown(mEditable, forwardDelEvent.getKeyCode(), 212 forwardDelEvent)); 213 214 assertThat(mEditable, hasEmojiCount(2)); 215 assertThat(mEditable, hasEmoji(EMOJI_FLAG)); 216 assertThat(mEditable, hasEmoji(EMOJI_GENDER)); 217 218 assertEquals(new TestString(EMOJI_FLAG).append(EMOJI_GENDER) 219 .withPrefix().withSuffix().toString(), mEditable.toString()); 220 } 221 222} 223