Home | History | Annotate | Download | only in method
      1 /*
      2  * Copyright (C) 2016 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 
     17 package android.text.method;
     18 
     19 import android.platform.test.annotations.Presubmit;
     20 import android.support.test.InstrumentationRegistry;
     21 import android.support.test.filters.SmallTest;
     22 import android.support.test.runner.AndroidJUnit4;
     23 import android.text.InputType;
     24 import android.util.KeyUtils;
     25 import android.view.KeyEvent;
     26 import android.widget.EditText;
     27 import android.widget.TextView.BufferType;
     28 
     29 import org.junit.Before;
     30 import org.junit.Test;
     31 import org.junit.runner.RunWith;
     32 
     33 /**
     34  * Test backspace key handling of {@link android.text.method.BaseKeyListener}.
     35  *
     36  * Only contains edge cases. For normal cases, see {@see android.text.method.cts.BackspaceTest}.
     37  * TODO: introduce test cases for surrogate pairs and replacement span.
     38  */
     39 
     40 @Presubmit
     41 @SmallTest
     42 @RunWith(AndroidJUnit4.class)
     43 public class BackspaceTest {
     44     private EditText mTextView;
     45 
     46     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
     47         public int getInputType() {
     48             return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
     49         }
     50     };
     51 
     52     @Before
     53     public void setup() {
     54         mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext());
     55     }
     56 
     57 
     58     // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
     59     // Then update the state to the result of TextView.
     60     private void backspace(final EditorState state, int modifiers) {
     61         mTextView.setText(state.mText, BufferType.EDITABLE);
     62         mTextView.setKeyListener(mKeyListener);
     63         mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
     64 
     65         final KeyEvent keyEvent = KeyUtils.generateKeyEvent(
     66             KeyEvent.KEYCODE_DEL, KeyEvent.ACTION_DOWN, modifiers);
     67         mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
     68 
     69         state.mText = mTextView.getText();
     70         state.mSelectionStart = mTextView.getSelectionStart();
     71         state.mSelectionEnd = mTextView.getSelectionEnd();
     72     }
     73 
     74     @Test
     75     public void testCombiningEnclosingKeycaps() {
     76         EditorState state = new EditorState();
     77 
     78         state.setByString("'1' U+E0101 U+20E3 |");
     79         backspace(state, 0);
     80         state.assertEquals("|");
     81 
     82         // multiple COMBINING ENCLOSING KEYCAP
     83         state.setByString("'1' U+20E3 U+20E3 |");
     84         backspace(state, 0);
     85         state.assertEquals("'1' U+20E3 |");
     86         backspace(state, 0);
     87         state.assertEquals("|");
     88 
     89         // Isolated COMBINING ENCLOSING KEYCAP
     90         state.setByString("U+20E3 |");
     91         backspace(state, 0);
     92         state.assertEquals("|");
     93 
     94         // Isolated multiple COMBINING ENCLOSING KEYCAP
     95         state.setByString("U+20E3 U+20E3 |");
     96         backspace(state, 0);
     97         state.assertEquals("U+20E3 |");
     98         backspace(state, 0);
     99         state.assertEquals("|");
    100     }
    101 
    102     @Test
    103     public void testVariationSelector() {
    104         EditorState state = new EditorState();
    105 
    106         // Isolated variation selector
    107         state.setByString("U+FE0F |");
    108         backspace(state, 0);
    109         state.assertEquals("|");
    110 
    111         state.setByString("U+E0100 |");
    112         backspace(state, 0);
    113         state.assertEquals("|");
    114 
    115         // Isolated multiple variation selectors
    116         state.setByString("U+FE0F U+FE0F |");
    117         backspace(state, 0);
    118         state.assertEquals("U+FE0F |");
    119         backspace(state, 0);
    120         state.assertEquals("|");
    121 
    122         state.setByString("U+FE0F U+E0100 |");
    123         backspace(state, 0);
    124         state.assertEquals("U+FE0F |");
    125         backspace(state, 0);
    126         state.assertEquals("|");
    127 
    128         state.setByString("U+E0100 U+FE0F |");
    129         backspace(state, 0);
    130         state.assertEquals("U+E0100 |");
    131         backspace(state, 0);
    132         state.assertEquals("|");
    133 
    134         state.setByString("U+E0100 U+E0100 |");
    135         backspace(state, 0);
    136         state.assertEquals("U+E0100 |");
    137         backspace(state, 0);
    138         state.assertEquals("|");
    139 
    140         // Multiple variation selectors
    141         state.setByString("'#' U+FE0F U+FE0F |");
    142         backspace(state, 0);
    143         state.assertEquals("'#' U+FE0F |");
    144         backspace(state, 0);
    145         state.assertEquals("|");
    146 
    147         state.setByString("'#' U+FE0F U+E0100 |");
    148         backspace(state, 0);
    149         state.assertEquals("'#' U+FE0F |");
    150         backspace(state, 0);
    151         state.assertEquals("|");
    152 
    153         state.setByString("U+845B U+E0100 U+FE0F |");
    154         backspace(state, 0);
    155         state.assertEquals("U+845B U+E0100 |");
    156         backspace(state, 0);
    157         state.assertEquals("|");
    158 
    159         state.setByString("U+845B U+E0100 U+E0100 |");
    160         backspace(state, 0);
    161         state.assertEquals("U+845B U+E0100 |");
    162         backspace(state, 0);
    163         state.assertEquals("|");
    164     }
    165 
    166     @Test
    167     public void testEmojiZWJSequence() {
    168         EditorState state = new EditorState();
    169 
    170         // U+200D is ZERO WIDTH JOINER.
    171         state.setByString("U+1F441 U+200D U+1F5E8 |");
    172         backspace(state, 0);
    173         state.assertEquals("|");
    174 
    175         state.setByString("U+1F441 U+200D U+1F5E8 U+FE0E |");
    176         backspace(state, 0);
    177         state.assertEquals("|");
    178 
    179         state.setByString("U+1F469 U+200D U+1F373 |");
    180         backspace(state, 0);
    181         state.assertEquals("|");
    182 
    183         state.setByString("U+1F487 U+200D U+2640 |");
    184         backspace(state, 0);
    185         state.assertEquals("|");
    186 
    187         state.setByString("U+1F487 U+200D U+2640 U+FE0F |");
    188         backspace(state, 0);
    189         state.assertEquals("|");
    190 
    191         state.setByString("U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468 |");
    192         backspace(state, 0);
    193         state.assertEquals("|");
    194 
    195         // Emoji modifier can be appended to the first emoji.
    196         state.setByString("U+1F469 U+1F3FB U+200D U+1F4BC |");
    197         backspace(state, 0);
    198         state.assertEquals("|");
    199 
    200         // End with ZERO WIDTH JOINER
    201         state.setByString("U+1F441 U+200D |");
    202         backspace(state, 0);
    203         state.assertEquals("U+1F441 |");
    204         backspace(state, 0);
    205         state.assertEquals("|");
    206 
    207         // Start with ZERO WIDTH JOINER
    208         state.setByString("U+200D U+1F5E8 |");
    209         backspace(state, 0);
    210         state.assertEquals("U+200D |");
    211         backspace(state, 0);
    212         state.assertEquals("|");
    213 
    214         state.setByString("U+FE0E U+200D U+1F5E8 |");
    215         backspace(state, 0);
    216         state.assertEquals("U+FE0E U+200D |");
    217         backspace(state, 0);
    218         state.assertEquals("U+FE0E |");
    219         backspace(state, 0);
    220         state.assertEquals("|");
    221 
    222         // Multiple ZERO WIDTH JOINER
    223         state.setByString("U+1F441 U+200D U+200D U+1F5E8 |");
    224         backspace(state, 0);
    225         state.assertEquals("U+1F441 U+200D U+200D |");
    226         backspace(state, 0);
    227         state.assertEquals("U+1F441 U+200D |");
    228         backspace(state, 0);
    229         state.assertEquals("U+1F441 |");
    230         backspace(state, 0);
    231         state.assertEquals("|");
    232 
    233         // Isolated ZERO WIDTH JOINER
    234         state.setByString("U+200D |");
    235         backspace(state, 0);
    236         state.assertEquals("|");
    237 
    238         // Isolated multiple ZERO WIDTH JOINER
    239         state.setByString("U+200D U+200D |");
    240         backspace(state, 0);
    241         state.assertEquals("U+200D |");
    242         backspace(state, 0);
    243         state.assertEquals("|");
    244     }
    245 
    246     @Test
    247     public void testFlags() {
    248         EditorState state = new EditorState();
    249 
    250         // Isolated regional indicator symbol
    251         state.setByString("U+1F1FA |");
    252         backspace(state, 0);
    253         state.assertEquals("|");
    254 
    255         // Odd numbered regional indicator symbols
    256         state.setByString("U+1F1FA U+1F1F8 U+1F1FA |");
    257         backspace(state, 0);
    258         state.assertEquals("U+1F1FA U+1F1F8 |");
    259         backspace(state, 0);
    260         state.assertEquals("|");
    261 
    262         // Incomplete sequence. (no tag_term: U+E007E)
    263         state.setByString("'a' U+1F3F4 U+E0067 'b' |");
    264         backspace(state, 0);
    265         state.assertEquals("'a' U+1F3F4 U+E0067 |");
    266         backspace(state, 0);
    267         state.assertEquals("'a' U+1F3F4 |");
    268         backspace(state, 0);
    269         state.assertEquals("'a' |");
    270 
    271         // No tag_base
    272         state.setByString("'a' U+E0067 U+E007F 'b' |");
    273         backspace(state, 0);
    274         state.assertEquals("'a' U+E0067 U+E007F |");
    275         backspace(state, 0);
    276         state.assertEquals("'a' U+E0067 |");
    277         backspace(state, 0);
    278         state.assertEquals("'a' |");
    279 
    280         // Isolated tag chars
    281         state.setByString("'a' U+E0067 U+E0067 'b' |");
    282         backspace(state, 0);
    283         state.assertEquals("'a' U+E0067 U+E0067 |");
    284         backspace(state, 0);
    285         state.assertEquals("'a' U+E0067 |");
    286         backspace(state, 0);
    287         state.assertEquals("'a' |");
    288 
    289         // Isolated tab term.
    290         state.setByString("'a' U+E007F U+E007F 'b' |");
    291         backspace(state, 0);
    292         state.assertEquals("'a' U+E007F U+E007F |");
    293         backspace(state, 0);
    294         state.assertEquals("'a' U+E007F |");
    295         backspace(state, 0);
    296         state.assertEquals("'a' |");
    297 
    298         // Immediate tag_term after tag_base
    299         state.setByString("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b' |");
    300         backspace(state, 0);
    301         state.assertEquals("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F |");
    302         backspace(state, 0);
    303         state.assertEquals("'a' U+1F3F4 U+E007F |");
    304         backspace(state, 0);
    305         state.assertEquals("'a' |");
    306     }
    307 
    308     @Test
    309     public void testEmojiModifier() {
    310         EditorState state = new EditorState();
    311 
    312         // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
    313         state.setByString("U+1F466 U+1F3FB |");
    314         backspace(state, 0);
    315         state.assertEquals("|");
    316 
    317         // Isolated emoji modifier
    318         state.setByString("U+1F3FB |");
    319         backspace(state, 0);
    320         state.assertEquals("|");
    321 
    322         // Isolated multiple emoji modifier
    323         state.setByString("U+1F3FB U+1F3FB |");
    324         backspace(state, 0);
    325         state.assertEquals("U+1F3FB |");
    326         backspace(state, 0);
    327         state.assertEquals("|");
    328 
    329         // Multiple emoji modifiers
    330         state.setByString("U+1F466 U+1F3FB U+1F3FB |");
    331         backspace(state, 0);
    332         state.assertEquals("U+1F466 U+1F3FB |");
    333         backspace(state, 0);
    334         state.assertEquals("|");
    335     }
    336 
    337     @Test
    338     public void testMixedEdgeCases() {
    339         EditorState state = new EditorState();
    340 
    341         // COMBINING ENCLOSING KEYCAP + variation selector
    342         state.setByString("'1' U+20E3 U+FE0F |");
    343         backspace(state, 0);
    344         state.assertEquals("'1' |");
    345         backspace(state, 0);
    346         state.assertEquals("|");
    347 
    348         // Variation selector + COMBINING ENCLOSING KEYCAP
    349         state.setByString("U+2665 U+FE0F U+20E3 |");
    350         backspace(state, 0);
    351         state.assertEquals("U+2665 U+FE0F |");
    352         backspace(state, 0);
    353         state.assertEquals("|");
    354 
    355         // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
    356         state.setByString("'1' U+20E3 U+200D |");
    357         backspace(state, 0);
    358         state.assertEquals("'1' U+20E3 |");
    359         backspace(state, 0);
    360         state.assertEquals("|");
    361 
    362         // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
    363         state.setByString("'1' U+20E3 U+200D U+1F5E8 |");
    364         backspace(state, 0);
    365         state.assertEquals("'1' U+20E3 U+200D |");
    366         backspace(state, 0);
    367         state.assertEquals("'1' U+20E3 |");
    368         backspace(state, 0);
    369         state.assertEquals("|");
    370 
    371         // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
    372         state.setByString("U+200D U+20E3 |");
    373         backspace(state, 0);
    374         state.assertEquals("U+200D |");
    375         backspace(state, 0);
    376         state.assertEquals("|");
    377 
    378         // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
    379         state.setByString("U+1F441 U+200D U+20E3 |");
    380         backspace(state, 0);
    381         state.assertEquals("U+1F441 U+200D |");
    382         backspace(state, 0);
    383         state.assertEquals("U+1F441 |");
    384         backspace(state, 0);
    385         state.assertEquals("|");
    386 
    387         // COMBINING ENCLOSING KEYCAP + regional indicator symbol
    388         state.setByString("'1' U+20E3 U+1F1FA |");
    389         backspace(state, 0);
    390         state.assertEquals("'1' U+20E3 |");
    391         backspace(state, 0);
    392         state.assertEquals("|");
    393 
    394         // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
    395         state.setByString("U+1F1FA U+20E3 |");
    396         backspace(state, 0);
    397         state.assertEquals("U+1F1FA |");
    398         backspace(state, 0);
    399         state.assertEquals("|");
    400 
    401         // COMBINING ENCLOSING KEYCAP + emoji modifier
    402         state.setByString("'1' U+20E3 U+1F3FB |");
    403         backspace(state, 0);
    404         state.assertEquals("'1' U+20E3 |");
    405         backspace(state, 0);
    406         state.assertEquals("|");
    407 
    408         // Emoji modifier + COMBINING ENCLOSING KEYCAP
    409         state.setByString("U+1F466 U+1F3FB U+20E3 |");
    410         backspace(state, 0);
    411         state.assertEquals("U+1f466 U+1F3FB |");
    412         backspace(state, 0);
    413         state.assertEquals("|");
    414 
    415         // Variation selector + end with ZERO WIDTH JOINER
    416         state.setByString("U+2665 U+FE0F U+200D |");
    417         backspace(state, 0);
    418         state.assertEquals("U+2665 U+FE0F |");
    419         backspace(state, 0);
    420         state.assertEquals("|");
    421 
    422         // Variation selector + ZERO WIDTH JOINER
    423         state.setByString("U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469 |");
    424         backspace(state, 0);
    425         state.assertEquals("|");
    426 
    427         // Start with ZERO WIDTH JOINER + variation selector
    428         state.setByString("U+200D U+FE0F |");
    429         backspace(state, 0);
    430         state.assertEquals("|");
    431 
    432         // ZERO WIDTH JOINER + variation selector
    433         state.setByString("U+1F469 U+200D U+FE0F |");
    434         backspace(state, 0);
    435         state.assertEquals("U+1F469 |");
    436         backspace(state, 0);
    437         state.assertEquals("|");
    438 
    439         // Variation selector + regional indicator symbol
    440         state.setByString("U+2665 U+FE0F U+1F1FA |");
    441         backspace(state, 0);
    442         state.assertEquals("U+2665 U+FE0F |");
    443         backspace(state, 0);
    444         state.assertEquals("|");
    445 
    446         // Regional indicator symbol + variation selector
    447         state.setByString("U+1F1FA U+FE0F |");
    448         backspace(state, 0);
    449         state.assertEquals("|");
    450 
    451         // Variation selector + emoji modifier
    452         state.setByString("U+2665 U+FE0F U+1F3FB |");
    453         backspace(state, 0);
    454         state.assertEquals("U+2665 U+FE0F |");
    455         backspace(state, 0);
    456         state.assertEquals("|");
    457 
    458         // Emoji modifier + variation selector
    459         state.setByString("U+1F466 U+1F3FB U+FE0F |");
    460         backspace(state, 0);
    461         state.assertEquals("U+1F466 |");
    462         backspace(state, 0);
    463         state.assertEquals("|");
    464 
    465         // Start withj ZERO WIDTH JOINER + regional indicator symbol
    466         state.setByString("U+200D U+1F1FA |");
    467         backspace(state, 0);
    468         state.assertEquals("U+200D |");
    469         backspace(state, 0);
    470         state.assertEquals("|");
    471 
    472         // ZERO WIDTH JOINER + Regional indicator symbol
    473         state.setByString("U+1F469 U+200D U+1F1FA |");
    474         backspace(state, 0);
    475         state.assertEquals("U+1F469 U+200D |");
    476         backspace(state, 0);
    477         state.assertEquals("U+1F469 |");
    478         backspace(state, 0);
    479         state.assertEquals("|");
    480 
    481         // Regional indicator symbol + end with ZERO WIDTH JOINER
    482         state.setByString("U+1F1FA U+200D |");
    483         backspace(state, 0);
    484         state.assertEquals("U+1F1FA |");
    485         backspace(state, 0);
    486         state.assertEquals("|");
    487 
    488         // Regional indicator symbol + ZERO WIDTH JOINER
    489         state.setByString("U+1F1FA U+200D U+1F469 |");
    490         backspace(state, 0);
    491         state.assertEquals("|");
    492 
    493         // Start with ZERO WIDTH JOINER + emoji modifier
    494         state.setByString("U+200D U+1F3FB |");
    495         backspace(state, 0);
    496         state.assertEquals("U+200D |");
    497         backspace(state, 0);
    498         state.assertEquals("|");
    499 
    500         // ZERO WIDTH JOINER + emoji modifier
    501         state.setByString("U+1F469 U+200D U+1F3FB |");
    502         backspace(state, 0);
    503         state.assertEquals("U+1F469 U+200D |");
    504         backspace(state, 0);
    505         state.assertEquals("U+1F469 |");
    506         backspace(state, 0);
    507         state.assertEquals("|");
    508 
    509         // Emoji modifier + end with ZERO WIDTH JOINER
    510         state.setByString("U+1F466 U+1F3FB U+200D |");
    511         backspace(state, 0);
    512         state.assertEquals("U+1F466 U+1F3FB |");
    513         backspace(state, 0);
    514         state.assertEquals("|");
    515 
    516         // Regional indicator symbol + Emoji modifier
    517         state.setByString("U+1F1FA U+1F3FB |");
    518         backspace(state, 0);
    519         state.assertEquals("U+1F1FA |");
    520         backspace(state, 0);
    521         state.assertEquals("|");
    522 
    523         // Emoji modifier + regional indicator symbol
    524         state.setByString("U+1F466 U+1F3FB U+1F1FA |");
    525         backspace(state, 0);
    526         state.assertEquals("U+1F466 U+1F3FB |");
    527         backspace(state, 0);
    528         state.assertEquals("|");
    529 
    530         // RIS + LF
    531         state.setByString("U+1F1E6 U+000A |");
    532         backspace(state, 0);
    533         state.assertEquals("U+1F1E6 |");
    534         backspace(state, 0);
    535         state.assertEquals("|");
    536     }
    537 }
    538