1ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka/* 2ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Copyright (C) 2016 The Android Open Source Project 3ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * 4ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License"); 5ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * you may not use this file except in compliance with the License. 6ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * You may obtain a copy of the License at 7ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * 8ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * http://www.apache.org/licenses/LICENSE-2.0 9ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * 10ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Unless required by applicable law or agreed to in writing, software 11ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS, 12ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * See the License for the specific language governing permissions and 14ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * limitations under the License. 15ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka */ 16ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 17ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakapackage android.text.method; 18ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 19869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanuimport android.support.test.InstrumentationRegistry; 2068089c81068cc93d3fd42e2f768fc3a2a0d08f3cSiyamed Sinirimport android.support.test.filters.SmallTest; 21bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport android.support.test.runner.AndroidJUnit4; 22ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.text.InputType; 23869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanuimport android.util.KeyUtils; 24ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.view.KeyEvent; 25869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanuimport android.widget.EditText; 26ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.widget.TextView.BufferType; 27bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport org.junit.Before; 28bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport org.junit.Test; 29bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanuimport org.junit.runner.RunWith; 30ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 31ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka/** 3268089c81068cc93d3fd42e2f768fc3a2a0d08f3cSiyamed Sinir * Test backspace key handling of {@link android.text.method.BaseKeyListener}. 33ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * 34132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * Only contains edge cases. For normal cases, see {@see android.text.method.cts.BackspaceTest}. 35132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * TODO: introduce test cases for surrogate pairs and replacement span. 36ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka */ 37bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu@SmallTest 38bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu@RunWith(AndroidJUnit4.class) 39869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanupublic class BackspaceTest { 40869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu private EditText mTextView; 41869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu 42ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka private static final BaseKeyListener mKeyListener = new BaseKeyListener() { 43ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public int getInputType() { 44ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; 45ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 46ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka }; 47ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 48869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu @Before 49869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu public void setup() { 50869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext()); 51869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu } 52869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu 53869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu 54ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event. 55ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Then update the state to the result of TextView. 56ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka private void backspace(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); 60ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 61869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu final KeyEvent keyEvent = KeyUtils.generateKeyEvent( 62869dd39c5a9c1e55a1d7ab796a05e5e710dff348Andrei Stingaceanu KeyEvent.KEYCODE_DEL, KeyEvent.ACTION_DOWN, modifiers); 63d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); 64ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 65ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.mText = mTextView.getText(); 66ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.mSelectionStart = mTextView.getSelectionStart(); 67ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.mSelectionEnd = mTextView.getSelectionEnd(); 68ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 69ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 70bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 71ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public void testCombiningEnclosingKeycaps() { 72ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka EditorState state = new EditorState(); 73ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 74328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("'1' U+E0101 U+20E3 |"); 75328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka backspace(state, 0); 76328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 77328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 78ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // multiple COMBINING ENCLOSING KEYCAP 79ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'1' U+20E3 U+20E3 |"); 80ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 81ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' U+20E3 |"); 82ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 83ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 84ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 85ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated COMBINING ENCLOSING KEYCAP 86ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+20E3 |"); 87ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 88ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 89ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 90ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated multiple COMBINING ENCLOSING KEYCAP 91ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+20E3 U+20E3 |"); 92ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 93ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+20E3 |"); 94ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 95ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 96ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 97ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 98bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 99ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public void testVariationSelector() { 100ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka EditorState state = new EditorState(); 101ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 102ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated variation selector 103ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+FE0F |"); 104ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 105ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 106ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 107ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+E0100 |"); 108ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 109ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 110ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 111ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated multiple variation selectors 112ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+FE0F U+FE0F |"); 113ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 114ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+FE0F |"); 115ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 116ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 117ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 118ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+FE0F U+E0100 |"); 119ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 120ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+FE0F |"); 121ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 122ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 123ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 124ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+E0100 U+FE0F |"); 125ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 126ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+E0100 |"); 127ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 128ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 129ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 130ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+E0100 U+E0100 |"); 131ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 132ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+E0100 |"); 133ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 134ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 135ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 136ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Multiple variation selectors 137ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'#' U+FE0F U+FE0F |"); 138ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 139ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'#' U+FE0F |"); 140ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 141ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 142ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 143ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'#' U+FE0F U+E0100 |"); 144ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 145ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'#' U+FE0F |"); 146ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 147ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 148ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 149ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+845B U+E0100 U+FE0F |"); 150ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 151ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+845B U+E0100 |"); 152ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 153ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 154ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 155ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+845B U+E0100 U+E0100 |"); 156ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 157ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+845B U+E0100 |"); 158ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 159ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 160ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 161ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 162bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 163ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public void testEmojiZWJSequence() { 164ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka EditorState state = new EditorState(); 165ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 166328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka // U+200D is ZERO WIDTH JOINER. 167328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("U+1F441 U+200D U+1F5E8 |"); 168328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka backspace(state, 0); 169328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 170328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 171328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("U+1F441 U+200D U+1F5E8 U+FE0E |"); 172328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka backspace(state, 0); 173328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 174328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 175beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka state.setByString("U+1F469 U+200D U+1F373 |"); 176beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka backspace(state, 0); 177beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka state.assertEquals("|"); 178beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka 179beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka state.setByString("U+1F487 U+200D U+2640 |"); 180beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka backspace(state, 0); 181beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka state.assertEquals("|"); 182beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka 183beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka state.setByString("U+1F487 U+200D U+2640 U+FE0F |"); 184beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka backspace(state, 0); 185beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka state.assertEquals("|"); 186beb21afc2e3aedd17a3fbcb044a7fa44c0daf69dSeigo Nonaka 187328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468 |"); 188328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka backspace(state, 0); 189328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 190328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 191bba8d97c369f02a9d1988217324724a24842079fSeigo Nonaka // Emoji modifier can be appended to the first emoji. 192bba8d97c369f02a9d1988217324724a24842079fSeigo Nonaka state.setByString("U+1F469 U+1F3FB U+200D U+1F4BC |"); 193bba8d97c369f02a9d1988217324724a24842079fSeigo Nonaka backspace(state, 0); 194bba8d97c369f02a9d1988217324724a24842079fSeigo Nonaka state.assertEquals("|"); 195bba8d97c369f02a9d1988217324724a24842079fSeigo Nonaka 196ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // End with ZERO WIDTH JOINER 197ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F441 U+200D |"); 198ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 199ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F441 |"); 200ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 201ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 202ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 203ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Start with ZERO WIDTH JOINER 204ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D U+1F5E8 |"); 205ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 206ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+200D |"); 207ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 208ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 209ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 210ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+FE0E U+200D U+1F5E8 |"); 211ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 212ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+FE0E U+200D |"); 213ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 214ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+FE0E |"); 215ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 216ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 217ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 218ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Multiple ZERO WIDTH JOINER 219ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F441 U+200D U+200D U+1F5E8 |"); 220ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 221ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F441 U+200D U+200D |"); 222ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 223ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F441 U+200D |"); 224ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 225ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F441 |"); 226ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 227ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 228ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 229ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated ZERO WIDTH JOINER 230ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D |"); 231ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 232ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 233ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 234ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated multiple ZERO WIDTH JOINER 235ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D U+200D |"); 236ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 237ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+200D |"); 238ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 239ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 240ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 241ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 242bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 243ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public void testFlags() { 244ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka EditorState state = new EditorState(); 245ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 246ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated regional indicator symbol 247ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA |"); 248ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 249ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 250ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 251ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Odd numbered regional indicator symbols 252ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA U+1F1F8 U+1F1FA |"); 253ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 254ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F1FA U+1F1F8 |"); 255ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 256ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 257d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 258d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Incomplete sequence. (no tag_term: U+E007E) 259d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("'a' U+1F3F4 U+E0067 'b' |"); 260d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 261d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+1F3F4 U+E0067 |"); 262d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 263d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+1F3F4 |"); 264d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 265d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' |"); 266d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 267d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // No tag_base 268d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("'a' U+E0067 U+E007F 'b' |"); 269d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 270d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+E0067 U+E007F |"); 271d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 272d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+E0067 |"); 273d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 274d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' |"); 275d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 276d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Isolated tag chars 277d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("'a' U+E0067 U+E0067 'b' |"); 278d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 279d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+E0067 U+E0067 |"); 280d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 281d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+E0067 |"); 282d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 283d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' |"); 284d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 285d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Isolated tab term. 286d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("'a' U+E007F U+E007F 'b' |"); 287d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 288d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+E007F U+E007F |"); 289d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 290d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+E007F |"); 291d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 292d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' |"); 293d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka 294d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka // Immediate tag_term after tag_base 295d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.setByString("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b' |"); 296d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 297d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F |"); 298d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 299d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' U+1F3F4 U+E007F |"); 300d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka backspace(state, 0); 301d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka state.assertEquals("'a' |"); 302ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 303ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 304bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 305ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public void testEmojiModifier() { 306ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka EditorState state = new EditorState(); 307ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 308328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2. 309328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.setByString("U+1F466 U+1F3FB |"); 310328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka backspace(state, 0); 311328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka state.assertEquals("|"); 312328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka 313ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated emoji modifier 314ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F3FB |"); 315ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 316ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 317ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 318ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Isolated multiple emoji modifier 319ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F3FB U+1F3FB |"); 320ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 321ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F3FB |"); 322ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 323ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 324ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 325ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Multiple emoji modifiers 326ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F466 U+1F3FB U+1F3FB |"); 327ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 328ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F466 U+1F3FB |"); 329ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 330ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 331ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 332ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 333bbe51f8290af05b4071c7ed44fcbaa98e2f85e13Andrei Stingaceanu @Test 334ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka public void testMixedEdgeCases() { 335ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka EditorState state = new EditorState(); 336ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 337ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // COMBINING ENCLOSING KEYCAP + variation selector 338ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'1' U+20E3 U+FE0F |"); 339ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 340ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' |"); 341ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 342ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 343ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 344ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Variation selector + COMBINING ENCLOSING KEYCAP 345ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+2665 U+FE0F U+20E3 |"); 346ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 347ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+2665 U+FE0F |"); 348ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 349ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 350ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 351ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER 352ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'1' U+20E3 U+200D |"); 353ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 354ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' U+20E3 |"); 355ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 356ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 357ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 358ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER 359ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'1' U+20E3 U+200D U+1F5E8 |"); 360ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 361ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' U+20E3 U+200D |"); 362ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 363ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' U+20E3 |"); 364ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 365ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 366ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 367ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP 368ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D U+20E3 |"); 369ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 370ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+200D |"); 371ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 372ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 373ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 374ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP 375ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F441 U+200D U+20E3 |"); 376ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 377ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F441 U+200D |"); 378ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 379ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F441 |"); 380ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 381ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 382ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 383ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // COMBINING ENCLOSING KEYCAP + regional indicator symbol 384ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'1' U+20E3 U+1F1FA |"); 385ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 386ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' U+20E3 |"); 387ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 388ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 389ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 390ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Regional indicator symbol + COMBINING ENCLOSING KEYCAP 391ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA U+20E3 |"); 392ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 393ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F1FA |"); 394ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 395ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 396ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 397ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // COMBINING ENCLOSING KEYCAP + emoji modifier 398ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("'1' U+20E3 U+1F3FB |"); 399ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 400ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("'1' U+20E3 |"); 401ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 402ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 403ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 404ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Emoji modifier + COMBINING ENCLOSING KEYCAP 405ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F466 U+1F3FB U+20E3 |"); 406ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 407ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1f466 U+1F3FB |"); 408ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 409ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 410ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 411ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Variation selector + end with ZERO WIDTH JOINER 412ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+2665 U+FE0F U+200D |"); 413ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 414ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+2665 U+FE0F |"); 415ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 416ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 417ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 418ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Variation selector + ZERO WIDTH JOINER 419ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469 |"); 420ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 421ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 422ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 423ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Start with ZERO WIDTH JOINER + variation selector 424ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D U+FE0F |"); 425ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 426ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 427ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 428ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // ZERO WIDTH JOINER + variation selector 429ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F469 U+200D U+FE0F |"); 430ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 431ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F469 |"); 432ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 433ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 434ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 435ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Variation selector + regional indicator symbol 436ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+2665 U+FE0F U+1F1FA |"); 437ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 438ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+2665 U+FE0F |"); 439ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 440ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 441ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 442ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Regional indicator symbol + variation selector 443ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA U+FE0F |"); 444ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 445ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 446ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 447ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Variation selector + emoji modifier 448ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+2665 U+FE0F U+1F3FB |"); 449ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 450ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+2665 U+FE0F |"); 451ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 452ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 453ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 454ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Emoji modifier + variation selector 455ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F466 U+1F3FB U+FE0F |"); 456ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 457ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F466 |"); 458ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 459ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 460ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 461ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Start withj ZERO WIDTH JOINER + regional indicator symbol 462ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D U+1F1FA |"); 463ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 464ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+200D |"); 465ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 466ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 467ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 468ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // ZERO WIDTH JOINER + Regional indicator symbol 469ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F469 U+200D U+1F1FA |"); 470ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 471ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F469 U+200D |"); 472ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 473ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F469 |"); 474ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 475ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 476ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 477ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Regional indicator symbol + end with ZERO WIDTH JOINER 478ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA U+200D |"); 479ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 480ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F1FA |"); 481ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 482ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 483ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 484ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Regional indicator symbol + ZERO WIDTH JOINER 485ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA U+200D U+1F469 |"); 486ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 487ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 488ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 489ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Start with ZERO WIDTH JOINER + emoji modifier 490ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+200D U+1F3FB |"); 491ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 492ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+200D |"); 493ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 494ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 495ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 496ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // ZERO WIDTH JOINER + emoji modifier 497ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F469 U+200D U+1F3FB |"); 498ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 499ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F469 U+200D |"); 500ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 501ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F469 |"); 502ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 503ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 504ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 505ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Emoji modifier + end with ZERO WIDTH JOINER 506ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F466 U+1F3FB U+200D |"); 507ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 508ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F466 U+1F3FB |"); 509ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 510ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 511ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 512ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Regional indicator symbol + Emoji modifier 513ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F1FA U+1F3FB |"); 514ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 515ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F1FA |"); 516ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 517ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 518ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka 519ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka // Emoji modifier + regional indicator symbol 520ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.setByString("U+1F466 U+1F3FB U+1F1FA |"); 521ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 522ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("U+1F466 U+1F3FB |"); 523ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka backspace(state, 0); 524ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka state.assertEquals("|"); 5256a643348de7f98439511909e924b10a53040791aSeigo Nonaka 5266a643348de7f98439511909e924b10a53040791aSeigo Nonaka // RIS + LF 5276a643348de7f98439511909e924b10a53040791aSeigo Nonaka state.setByString("U+1F1E6 U+000A |"); 5286a643348de7f98439511909e924b10a53040791aSeigo Nonaka backspace(state, 0); 5296a643348de7f98439511909e924b10a53040791aSeigo Nonaka state.assertEquals("U+1F1E6 |"); 5306a643348de7f98439511909e924b10a53040791aSeigo Nonaka backspace(state, 0); 5316a643348de7f98439511909e924b10a53040791aSeigo Nonaka state.assertEquals("|"); 532ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka } 533ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka} 534