Home | History | Annotate | Download | only in text
      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  */
     16 package androidx.emoji.text;
     17 
     18 import static androidx.emoji.util.Emoji.EMOJI_FLAG;
     19 import static androidx.emoji.util.Emoji.EMOJI_WITH_ZWJ;
     20 import static androidx.emoji.util.EmojiMatcher.hasEmoji;
     21 import static androidx.emoji.util.EmojiMatcher.hasEmojiCount;
     22 
     23 import static org.hamcrest.MatcherAssert.assertThat;
     24 import static org.hamcrest.core.IsNot.not;
     25 import static org.junit.Assert.assertEquals;
     26 import static org.junit.Assert.assertFalse;
     27 import static org.junit.Assert.assertTrue;
     28 import static org.mockito.Mockito.mock;
     29 
     30 import android.annotation.SuppressLint;
     31 import android.support.test.filters.SdkSuppress;
     32 import android.support.test.filters.SmallTest;
     33 import android.support.test.runner.AndroidJUnit4;
     34 import android.text.Editable;
     35 import android.text.Selection;
     36 import android.text.SpannableStringBuilder;
     37 import android.view.inputmethod.InputConnection;
     38 
     39 import androidx.emoji.util.Emoji;
     40 import androidx.emoji.util.TestString;
     41 
     42 import org.junit.Before;
     43 import org.junit.BeforeClass;
     44 import org.junit.Test;
     45 import org.junit.runner.RunWith;
     46 
     47 @SmallTest
     48 @RunWith(AndroidJUnit4.class)
     49 @SdkSuppress(minSdkVersion = 19)
     50 public class SoftDeleteTest {
     51     private InputConnection mInputConnection;
     52     private TestString mTestString;
     53     private Editable mEditable;
     54 
     55     @BeforeClass
     56     public static void setupEmojiCompat() {
     57         EmojiCompat.reset(TestConfigBuilder.config());
     58     }
     59 
     60     @Before
     61     public void setup() {
     62         mInputConnection = mock(InputConnection.class);
     63         mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
     64         mEditable = new SpannableStringBuilder(mTestString.toString());
     65         EmojiCompat.get().process(mEditable);
     66         assertThat(mEditable, hasEmojiCount(1));
     67         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
     68     }
     69 
     70     @Test
     71     public void testDelete_doesNotDelete_whenSelectionIsUndefined() {
     72         // no selection is set on editable
     73         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
     74                 1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
     75 
     76         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
     77         assertEquals(mTestString.toString(), mEditable.toString());
     78     }
     79 
     80     @Test
     81     public void testDelete_doesNotDelete_whenThereIsSelectionLongerThanZero() {
     82         Selection.setSelection(mEditable, mTestString.emojiStartIndex(),
     83                 mTestString.emojiEndIndex() + 1);
     84 
     85         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
     86                 1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
     87 
     88         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
     89         assertEquals(mTestString.toString(), mEditable.toString());
     90     }
     91 
     92     @Test
     93     public void testDelete_withNullEditable() {
     94         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
     95 
     96         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, null,
     97                 1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
     98 
     99         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
    100         assertEquals(mTestString.toString(), mEditable.toString());
    101     }
    102 
    103     @Test
    104     public void testDelete_withNullInputConnection() {
    105         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
    106 
    107         assertFalse(EmojiCompat.handleDeleteSurroundingText(null, mEditable,
    108                 1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
    109 
    110         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
    111         assertEquals(mTestString.toString(), mEditable.toString());
    112     }
    113 
    114     @SuppressLint("Range")
    115     @Test
    116     public void testDelete_withInvalidLength() {
    117         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
    118 
    119         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    120                 -1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
    121 
    122         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
    123         assertEquals(mTestString.toString(), mEditable.toString());
    124     }
    125 
    126     @SuppressLint("Range")
    127     @Test
    128     public void testDelete_withInvalidAfterLength() {
    129         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
    130 
    131         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    132                 0 /*beforeLength*/, -1 /*afterLength*/, false /*inCodePoints*/));
    133 
    134         assertThat(mEditable, hasEmoji(EMOJI_WITH_ZWJ));
    135         assertEquals(mTestString.toString(), mEditable.toString());
    136     }
    137 
    138     @Test
    139     public void testDelete_backward() {
    140         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
    141 
    142         // backwards delete 1 character, it will delete the emoji
    143         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    144                 1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
    145 
    146         assertThat(mEditable, not(hasEmoji()));
    147         assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
    148     }
    149 
    150     @Test
    151     public void testDelete_backward_inCodepoints() {
    152         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
    153 
    154         // backwards delete 1 character, it will delete the emoji
    155         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    156                 1 /*beforeLength*/, 0 /*afterLength*/, true /*inCodePoints*/));
    157 
    158         assertThat(mEditable, not(hasEmoji()));
    159         assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
    160     }
    161 
    162     @Test
    163     public void testDelete_forward() {
    164         Selection.setSelection(mEditable, mTestString.emojiStartIndex());
    165 
    166         // forward delete 1 character, it will dele the emoji.
    167         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    168                 0 /*beforeLength*/, 1 /*afterLength*/, false /*inCodePoints*/));
    169 
    170         assertThat(mEditable, not(hasEmoji()));
    171         assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
    172     }
    173 
    174     @Test
    175     public void testDelete_forward_inCodepoints() {
    176         Selection.setSelection(mEditable, mTestString.emojiStartIndex());
    177 
    178         // forward delete 1 codepoint, it will delete the emoji.
    179         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    180                 0 /*beforeLength*/, 1 /*afterLength*/, false /*inCodePoints*/));
    181 
    182         assertThat(mEditable, not(hasEmoji()));
    183         assertEquals(new TestString().withPrefix().withSuffix().toString(), mEditable.toString());
    184     }
    185 
    186     @Test
    187     public void testDelete_backward_doesNotDeleteWhenSelectionAtCharSequenceStart() {
    188         // make sure selection at 0 does not do something weird for backward delete
    189         Selection.setSelection(mEditable, 0);
    190 
    191         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    192                 1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
    193 
    194         assertThat(mEditable, hasEmoji());
    195         assertEquals(mTestString.toString(), mEditable.toString());
    196     }
    197 
    198     @Test
    199     public void testDelete_forward_doesNotDeleteWhenSelectionAtCharSequenceEnd() {
    200         // make sure selection at end does not do something weird for forward delete
    201         Selection.setSelection(mEditable, mTestString.emojiEndIndex());
    202 
    203         assertFalse(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    204                 0 /*beforeLength*/, 1 /*afterLength*/, false /*inCodePoints*/));
    205 
    206         assertThat(mEditable, hasEmoji());
    207         assertEquals(mTestString.toString(), mEditable.toString());
    208     }
    209 
    210     @Test
    211     public void testDelete_withMultipleCharacters() {
    212         // prepare string as abc[emoji]def
    213         mTestString = new TestString(EMOJI_FLAG);
    214         mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
    215         EmojiCompat.get().process(mEditable);
    216 
    217         // set the selection in the middle of emoji
    218         Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
    219 
    220         // delete 4 characters forward, 4 character backwards
    221         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    222                 4 /*beforeLength*/, 4 /*afterLength*/, false /*inCodePoints*/));
    223 
    224         assertThat(mEditable, not(hasEmoji()));
    225         assertEquals("af", mEditable.toString());
    226     }
    227 
    228     @Test
    229     public void testDelete_withMultipleCodepoints() {
    230         // prepare string as abc[emoji]def
    231         mTestString = new TestString(EMOJI_FLAG);
    232         mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
    233         EmojiCompat.get().process(mEditable);
    234 
    235         // set the selection in the middle of emoji
    236         Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
    237 
    238         // delete 3 codepoints forward, 3 codepoints backwards
    239         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    240                 3 /*beforeLength*/, 3 /*afterLength*/, true /*inCodePoints*/));
    241 
    242         assertThat(mEditable, not(hasEmoji()));
    243         assertEquals("af", mEditable.toString());
    244     }
    245 
    246     @Test
    247     public void testDelete_withMultipleCharacters_withDeleteLengthLongerThanString() {
    248         // prepare string as abc[emoji]def
    249         mTestString = new TestString(EMOJI_FLAG);
    250         mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
    251         EmojiCompat.get().process(mEditable);
    252 
    253         // set the selection in the middle of emoji
    254         Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
    255 
    256         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    257                 100 /*beforeLength*/, 100 /*afterLength*/, false /*inCodePoints*/));
    258 
    259         assertThat(mEditable, not(hasEmoji()));
    260         assertEquals("", mEditable.toString());
    261     }
    262 
    263     @Test
    264     public void testDelete_withMultipleCodepoints_withDeleteLengthLongerThanString() {
    265         // prepare string as abc[emoji]def
    266         mTestString = new TestString(EMOJI_FLAG);
    267         mEditable = new SpannableStringBuilder("abc" + mTestString.toString() + "def");
    268         EmojiCompat.get().process(mEditable);
    269 
    270         // set the selection in the middle of emoji
    271         Selection.setSelection(mEditable, "abc".length() + EMOJI_FLAG.charCount() / 2);
    272 
    273         assertTrue(EmojiCompat.handleDeleteSurroundingText(mInputConnection, mEditable,
    274                 100 /*beforeLength*/, 100 /*afterLength*/, true /*inCodePoints*/));
    275 
    276         assertThat(mEditable, not(hasEmoji()));
    277         assertEquals("", mEditable.toString());
    278     }
    279 }
    280