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