123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka/* 223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Copyright (C) 2016 The Android Open Source Project 323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * 423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License"); 523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * you may not use this file except in compliance with the License. 623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * You may obtain a copy of the License at 723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * 823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * http://www.apache.org/licenses/LICENSE-2.0 923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * 1023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Unless required by applicable law or agreed to in writing, software 1123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS, 1223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * See the License for the specific language governing permissions and 1423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * limitations under the License. 1523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka */ 1623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 1723a67678e3848e2465518769236139e6cafac2eeSeigo Nonakapackage android.text.method; 1823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 19869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanuimport android.support.test.InstrumentationRegistry; 2068089c81068cc93d3fd42e2f768fc3a2a0d08f3cSiyamed Sinirimport android.support.test.filters.SmallTest; 21bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport android.support.test.runner.AndroidJUnit4; 2223a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.text.InputType; 23869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanuimport android.util.KeyUtils; 2423a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.view.KeyEvent; 25869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanuimport android.widget.EditText; 2623a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.widget.TextView.BufferType; 2723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 28bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport org.junit.Before; 29bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport org.junit.Test; 30bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport org.junit.runner.RunWith; 31bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu 3223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka/** 3323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Test forward delete key handling of {@link android.text.method.BaseKeyListener}. 3423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * 35132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * Only contains edge cases. For normal cases, see {@see android.text.method.cts.ForwardDeleteTest}. 36132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * TODO: introduce test cases for surrogate pairs and replacement span. 3723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka */ 38bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu@SmallTest 39bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu@RunWith(AndroidJUnit4.class) 40869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanupublic class ForwardDeleteTest { 41869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu private EditText mTextView; 42869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu 4323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka private static final BaseKeyListener mKeyListener = new BaseKeyListener() { 4423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public int getInputType() { 4523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; 4623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 4723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka }; 4823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 49869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu @Before 50869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu public void setup() { 51869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext()); 52869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu } 53869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu 5423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event. 5523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Then update the state to the result of TextView. 5623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka private void forwardDelete(final EditorState state, int modifiers) { 57d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka mTextView.setText(state.mText, BufferType.EDITABLE); 58d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka mTextView.setKeyListener(mKeyListener); 59d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); 6023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 61869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu final KeyEvent keyEvent = KeyUtils.generateKeyEvent( 62869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu KeyEvent.KEYCODE_FORWARD_DEL, KeyEvent.ACTION_DOWN, modifiers); 63d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); 6423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 6523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.mText = mTextView.getText(); 6623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.mSelectionStart = mTextView.getSelectionStart(); 6723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.mSelectionEnd = mTextView.getSelectionEnd(); 6823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 6923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 70bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 7123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public void testCombiningEnclosingKeycaps() { 7223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka EditorState state = new EditorState(); 7323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 7423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // multiple COMBINING ENCLOSING KEYCAP 7523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '1' U+20E3 U+20E3"); 7623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 7723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 7823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 7923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated COMBINING ENCLOSING KEYCAP 8023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+20E3"); 8123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 8223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 8323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 8423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated multiple COMBINING ENCLOSING KEYCAP 8523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+20E3 U+20E3"); 8623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 8723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 8823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 8923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 90bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 9123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public void testVariationSelector() { 9223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka EditorState state = new EditorState(); 9323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 9423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated variation selectors 9523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+FE0F"); 9623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 9723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 9823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 9923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+E0100"); 10023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 10123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 10223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 10323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated multiple variation selectors 10423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+FE0F U+FE0F"); 10523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 10623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 10723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 10823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+FE0F U+E0100"); 10923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 11023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 11123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 11223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+E0100 U+FE0F"); 11323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 11423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 11523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 11623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+E0100 U+E0100"); 11723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 11823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 11923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 12023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Multiple variation selectors 12123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '#' U+FE0F U+FE0F"); 12223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 12323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 12423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 12523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '#' U+FE0F U+E0100"); 12623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 12723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 12823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 12923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+845B U+E0100 U+FE0F"); 13023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 13123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 13223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 13323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+845B U+E0100 U+E0100"); 13423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 13523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 13623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 13723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 138bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 13923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public void testEmojiZeroWidthJoinerSequence() { 14023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka EditorState state = new EditorState(); 14123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 142328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka // U+200D is ZERO WIDTH JOINER. 143328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("| U+1F441 U+200D U+1F5E8"); 144328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka forwardDelete(state, 0); 145328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 146328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 147328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("| U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468"); 148328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka forwardDelete(state, 0); 149328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 150328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 15123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // End with ZERO WIDTH JOINER 15223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F441 U+200D"); 15323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 15423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 15523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 15623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Start with ZERO WIDTH JOINER 15723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D U+1F5E8"); 15823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 15923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F5E8"); 16023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 16123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 16223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 16323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Multiple ZERO WIDTH JOINER 16423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F441 U+200D U+200D U+1F5E8"); 16523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 16623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F5E8"); 16723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 16823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 16923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 17023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated ZERO WIDTH JOINER 17123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D"); 17223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 17323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 17423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 17523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated multiple ZERO WIDTH JOINER 17623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D U+200D"); 17723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 17823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 17923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 18023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 181bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 18223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public void testFlags() { 18323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka EditorState state = new EditorState(); 18423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 18523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated regional indicator symbol 18623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA"); 18723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 18823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 18923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 19023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Odd numbered regional indicator symbols 19123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA U+1F1F8 U+1F1FA"); 19223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 19323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F1FA"); 19423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 19523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 196d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 197d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Incomplete sequence. (no tag_term:U+E007E) 198d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("| 'a' U+1F3F4 U+E0067 'b'"); 199d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 200d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| U+1F3F4 U+E0067 'b'"); 201d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 202d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| 'b'"); 203d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 204d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // No tag_base 205d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("| 'a' U+E0067 U+E007F 'b'"); 206d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 207d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| 'b'"); 208d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 209d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Isolated tag chars 210d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("| 'a' U+E0067 U+E0067 'b'"); 211d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 212d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| 'b'"); 213d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 214d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Isolated tag base. 215d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("| 'a' U+1F3F4 U+1F3F4 'b'"); 216d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 217d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| U+1F3F4 U+1F3F4 'b'"); 218d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 219d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| U+1F3F4 'b'"); 220d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 221d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| 'b'"); 222d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 223d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Isolated tab term. 224d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("| 'a' U+E007F U+E007F 'b'"); 225d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 226d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| 'b'"); 227d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 228d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Immediate tag_term after tag_base 229d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("| 'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b'"); 230d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 231d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| U+1F3F4 U+E007F U+1F3F4 U+E007F 'b'"); 232d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 233d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| U+1F3F4 U+E007F 'b'"); 234d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka forwardDelete(state, 0); 235d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("| 'b'"); 23623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 23723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 238bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 23923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public void testEmojiModifier() { 24023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka EditorState state = new EditorState(); 24123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 242328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2. 243328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("| U+1F466 U+1F3FB"); 244328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka forwardDelete(state, 0); 245328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 246328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 24723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated emoji modifier 24823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F3FB"); 24923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 25023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 25123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 25223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Isolated multiple emoji modifier 25323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F3FB U+1F3FB"); 25423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 25523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F3FB"); 25623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 25723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 25823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 25923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Multiple emoji modifiers 26023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F466 U+1F3FB U+1F3FB"); 26123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 26223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F3FB"); 26323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 26423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 26523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 26623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 267bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 26823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka public void testMixedEdgeCases() { 26923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka EditorState state = new EditorState(); 27023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 27123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // COMBINING ENCLOSING KEYCAP + variation selector 27223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '1' U+20E3 U+FE0F"); 27323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 27423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 27523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 27623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Variation selector + COMBINING ENCLOSING KEYCAP 27723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+2665 U+FE0F U+20E3"); 27823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 27923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 28023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 28123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER 28223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '1' U+20E3 U+200D"); 28323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 28423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 28523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 28623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER 28723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '1' U+20E3 U+200D U+1F5E8"); 28823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 28923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F5E8 "); 29023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 29123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP 29223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D U+20E3"); 29323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 29423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 29523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 29623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP 29723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F441 U+200D U+20E3"); 29823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 29923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 30023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 30123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // COMBINING ENCLOSING KEYCAP + regional indicator symbol 30223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '1' U+20E3 U+1F1FA"); 30323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 30423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F1FA"); 30523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 30623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 30723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 30823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Regional indicator symbol + COMBINING ENCLOSING KEYCAP 30923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA U+20E3"); 31023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 31123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 31223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 31323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // COMBINING ENCLOSING KEYCAP + emoji modifier 31423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| '1' U+20E3 U+1F3FB"); 31523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 31623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F3FB"); 31723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 31823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Emoji modifier + COMBINING ENCLOSING KEYCAP 31923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F466 U+1F3FB U+20E3"); 32023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 32123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 32223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 32323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Variation selector + end with ZERO WIDTH JOINER 32423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+2665 U+FE0F U+200D"); 32523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 32623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 32723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 32823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Variation selector + ZERO WIDTH JOINER 32923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469"); 33023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 33123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 33223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 33323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Start with ZERO WIDTH JOINER + variation selector 33423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D U+FE0F"); 33523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 33623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 33723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 33823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // ZERO WIDTH JOINER + variation selector 33923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F469 U+200D U+FE0F"); 34023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 34123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 34223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 34323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Variation selector + regional indicator symbol 34423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+2665 U+FE0F U+1F1FA"); 34523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 34623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F1FA"); 34723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 34823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 34923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 35023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Regional indicator symbol + variation selector 35123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA U+FE0F"); 35223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 35323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 35423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 35523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Variation selector + emoji modifier 35623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+2665 U+FE0F U+1F3FB"); 35723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 35823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F3FB"); 35923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 36023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Emoji modifier + variation selector 36123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F466 U+1F3FB U+FE0F"); 36223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 36323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 36423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 36523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Start with ZERO WIDTH JOINER + regional indicator symbol 36623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D U+1F1FA"); 36723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 36823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F1FA"); 36923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 37023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 37123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 37223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // ZERO WIDTH JOINER + regional indicator symbol 37323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F469 U+200D U+1F1FA"); 37423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 3754fbf85b02f3b06882a0ec46d7fbe784d2d8ae1fbRoozbeh Pournader state.assertEquals("| U+1F1FA"); 3764fbf85b02f3b06882a0ec46d7fbe784d2d8ae1fbRoozbeh Pournader forwardDelete(state, 0); 3771e22227117f6ad86e9efe2a2ca2cca1fc456f07eSeigo Nonaka state.assertEquals("|"); 37823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 37923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Regional indicator symbol + end with ZERO WIDTH JOINER 38023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA U+200D"); 38123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 38223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 38323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 38423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Regional indicator symbol + ZERO WIDTH JOINER 38523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA U+200D U+1F469"); 38623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 3874fbf85b02f3b06882a0ec46d7fbe784d2d8ae1fbRoozbeh Pournader state.assertEquals("| U+1F469"); 3884fbf85b02f3b06882a0ec46d7fbe784d2d8ae1fbRoozbeh Pournader forwardDelete(state, 0); 38923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 39023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 39123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Start with ZERO WIDTH JOINER + emoji modifier 39223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+200D U+1F3FB"); 39323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 39423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F3FB"); 39523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 39623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // ZERO WIDTH JOINER + emoji modifier 39723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F469 U+200D U+1F3FB"); 39823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 3991e22227117f6ad86e9efe2a2ca2cca1fc456f07eSeigo Nonaka state.assertEquals("|"); 40023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 40123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Emoji modifier + end with ZERO WIDTH JOINER 40223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F466 U+1F3FB U+200D"); 40323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 40423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 40523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 40623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Emoji modifier + ZERO WIDTH JOINER 40723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F466 U+1F3FB U+200D U+1F469"); 40823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 4094fbf85b02f3b06882a0ec46d7fbe784d2d8ae1fbRoozbeh Pournader state.assertEquals("| U+1F469"); 4104fbf85b02f3b06882a0ec46d7fbe784d2d8ae1fbRoozbeh Pournader forwardDelete(state, 0); 41123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 41223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 41323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Regional indicator symbol + emoji modifier 41423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F1FA U+1F3FB"); 41523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 41623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F3FB"); 41723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 41823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 41923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka 42023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka // Emoji modifier + regional indicator symbol 42123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.setByString("| U+1F466 U+1F3FB U+1F1FA"); 42223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 42323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("| U+1F1FA"); 42423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka forwardDelete(state, 0); 42523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka state.assertEquals("|"); 42623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka } 42723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka} 428