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
19ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.app.Activity;
20ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.test.suitebuilder.annotation.SmallTest;
21ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.test.suitebuilder.annotation.Suppress;
22ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.text.InputType;
23ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.text.method.BaseKeyListener;
24ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.text.method.KeyListenerTestCase;
25ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.view.KeyEvent;
26ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.widget.EditText;
27ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakaimport android.widget.TextView.BufferType;
28ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
29ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka/**
30ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Test backspace key handling of {@link android.text.method.BaseKeyListner}.
31ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka *
32132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * Only contains edge cases. For normal cases, see {@see android.text.method.cts.BackspaceTest}.
33132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * TODO: introduce test cases for surrogate pairs and replacement span.
34ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka */
35ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakapublic class BackspaceTest extends KeyListenerTestCase {
36ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
37ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        public int getInputType() {
38ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
39ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        }
40ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    };
41ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
42ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
43ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    // Then update the state to the result of TextView.
44ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    private void backspace(final EditorState state, int modifiers) {
45ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        mActivity.runOnUiThread(new Runnable() {
46ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka            public void run() {
47ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka                mTextView.setText(state.mText, BufferType.EDITABLE);
48ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka                mTextView.setKeyListener(mKeyListener);
49ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka                mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
50ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka            }
51ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        });
52ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        mInstrumentation.waitForIdleSync();
53ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        assertTrue(mTextView.hasWindowFocus());
54ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
55ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
56ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        mActivity.runOnUiThread(new Runnable() {
57ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka            public void run() {
58ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka                mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
59ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka            }
60ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        });
61ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        mInstrumentation.waitForIdleSync();
62ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
63ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.mText = mTextView.getText();
64ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.mSelectionStart = mTextView.getSelectionStart();
65ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.mSelectionEnd = mTextView.getSelectionEnd();
66ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
67ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
68ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    @SmallTest
69ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public void testCombiningEnclosingKeycaps() {
70ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        EditorState state = new EditorState();
71ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
72328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("'1' U+E0101 U+20E3 |");
73328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        backspace(state, 0);
74328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
75328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
76ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // multiple COMBINING ENCLOSING KEYCAP
77ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'1' U+20E3 U+20E3 |");
78ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
79ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' U+20E3 |");
80ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
81ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
82ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
83ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated COMBINING ENCLOSING KEYCAP
84ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+20E3 |");
85ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
86ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
87ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
88ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated multiple COMBINING ENCLOSING KEYCAP
89ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+20E3 U+20E3 |");
90ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
91ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+20E3 |");
92ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
93ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
94ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
95ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
96ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    @SmallTest
97ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public void testVariationSelector() {
98ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        EditorState state = new EditorState();
99ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
100ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated variation selector
101ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+FE0F |");
102ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
103ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
104ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
105ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+E0100 |");
106ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
107ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
108ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
109ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated multiple variation selectors
110ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+FE0F U+FE0F |");
111ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
112ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+FE0F |");
113ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
114ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
115ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
116ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+FE0F U+E0100 |");
117ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
118ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+FE0F |");
119ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
120ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
121ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
122ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+E0100 U+FE0F |");
123ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
124ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+E0100 |");
125ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
126ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
127ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
128ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+E0100 U+E0100 |");
129ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
130ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+E0100 |");
131ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
132ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
133ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
134ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Multiple variation selectors
135ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'#' U+FE0F U+FE0F |");
136ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
137ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'#' U+FE0F |");
138ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
139ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
140ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
141ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'#' U+FE0F U+E0100 |");
142ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
143ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'#' U+FE0F |");
144ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
145ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
146ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
147ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+845B U+E0100 U+FE0F |");
148ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
149ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+845B U+E0100 |");
150ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
151ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
152ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
153ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+845B U+E0100 U+E0100 |");
154ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
155ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+845B U+E0100 |");
156ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
157ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
158ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
159ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
160ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    @SmallTest
161ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public void testEmojiZWJSequence() {
162ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        EditorState state = new EditorState();
163ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
164328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        // U+200D is ZERO WIDTH JOINER.
165328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("U+1F441 U+200D U+1F5E8 |");
166328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        backspace(state, 0);
167328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
168328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
169328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("U+1F441 U+200D U+1F5E8 U+FE0E |");
170328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        backspace(state, 0);
171328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
172328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
173328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468 |");
174328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        backspace(state, 0);
175328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
176328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
177ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // End with ZERO WIDTH JOINER
178ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F441 U+200D |");
179ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
180ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F441 |");
181ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
182ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
183ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
184ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Start with ZERO WIDTH JOINER
185ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D U+1F5E8 |");
186ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
187ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+200D |");
188ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
189ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
190ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
191ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+FE0E U+200D U+1F5E8 |");
192ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
193ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+FE0E U+200D |");
194ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
195ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+FE0E |");
196ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
197ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
198ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
199ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Multiple ZERO WIDTH JOINER
200ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F441 U+200D U+200D U+1F5E8 |");
201ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
202ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F441 U+200D U+200D |");
203ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
204ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F441 U+200D |");
205ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
206ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F441 |");
207ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
208ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
209ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
210ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated ZERO WIDTH JOINER
211ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D |");
212ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
213ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
214ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
215ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated multiple ZERO WIDTH JOINER
216ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D U+200D |");
217ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
218ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+200D |");
219ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
220ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
221ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
222ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
223ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    @SmallTest
224ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public void testFlags() {
225ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        EditorState state = new EditorState();
226ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
227ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated regional indicator symbol
228ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA |");
229ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
230ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
231ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
232ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Odd numbered regional indicator symbols
233ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA U+1F1F8 U+1F1FA |");
234ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
235ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F1FA U+1F1F8 |");
236ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
237ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
238ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
239ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
240ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    @SmallTest
241ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public void testEmojiModifier() {
242ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        EditorState state = new EditorState();
243ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
244328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
245328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("U+1F466 U+1F3FB |");
246328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        backspace(state, 0);
247328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
248328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
249ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated emoji modifier
250ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F3FB |");
251ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
252ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
253ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
254ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Isolated multiple emoji modifier
255ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F3FB U+1F3FB |");
256ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
257ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F3FB |");
258ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
259ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
260ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
261ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Multiple emoji modifiers
262ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F466 U+1F3FB U+1F3FB |");
263ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
264ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F466 U+1F3FB |");
265ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
266ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
267ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
268ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
269ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    @SmallTest
270ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public void testMixedEdgeCases() {
271ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        EditorState state = new EditorState();
272ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
273ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // COMBINING ENCLOSING KEYCAP + variation selector
274ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'1' U+20E3 U+FE0F |");
275ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
276ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' |");
277ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
278ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
279ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
280ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Variation selector + COMBINING ENCLOSING KEYCAP
281ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+2665 U+FE0F U+20E3 |");
282ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
283ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+2665 U+FE0F |");
284ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
285ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
286ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
287ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
288ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'1' U+20E3 U+200D |");
289ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
290ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' U+20E3 |");
291ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
292ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
293ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
294ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
295ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'1' U+20E3 U+200D U+1F5E8 |");
296ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
297ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' U+20E3 U+200D |");
298ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
299ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' U+20E3 |");
300ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
301ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
302ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
303ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
304ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D U+20E3 |");
305ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
306ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+200D |");
307ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
308ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
309ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
310ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
311ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F441 U+200D U+20E3 |");
312ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
313ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F441 U+200D |");
314ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
315ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F441 |");
316ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
317ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
318ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
319ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // COMBINING ENCLOSING KEYCAP + regional indicator symbol
320ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'1' U+20E3 U+1F1FA |");
321ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
322ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' U+20E3 |");
323ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
324ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
325ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
326ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
327ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA U+20E3 |");
328ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
329ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F1FA |");
330ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
331ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
332ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
333ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // COMBINING ENCLOSING KEYCAP + emoji modifier
334ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("'1' U+20E3 U+1F3FB |");
335ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
336ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("'1' U+20E3 |");
337ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
338ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
339ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
340ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Emoji modifier + COMBINING ENCLOSING KEYCAP
341ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F466 U+1F3FB U+20E3 |");
342ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
343ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1f466 U+1F3FB |");
344ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
345ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
346ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
347ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Variation selector + end with ZERO WIDTH JOINER
348ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+2665 U+FE0F U+200D |");
349ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
350ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+2665 U+FE0F |");
351ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
352ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
353ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
354ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Variation selector + ZERO WIDTH JOINER
355ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469 |");
356ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
357ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
358ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
359ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Start with ZERO WIDTH JOINER + variation selector
360ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D U+FE0F |");
361ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
362ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
363ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
364ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // ZERO WIDTH JOINER + variation selector
365ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F469 U+200D U+FE0F |");
366ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
367ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F469 |");
368ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
369ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
370ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
371ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Variation selector + regional indicator symbol
372ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+2665 U+FE0F U+1F1FA |");
373ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
374ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+2665 U+FE0F |");
375ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
376ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
377ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
378ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Regional indicator symbol + variation selector
379ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA U+FE0F |");
380ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
381ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
382ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
383ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Variation selector + emoji modifier
384ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+2665 U+FE0F U+1F3FB |");
385ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
386ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+2665 U+FE0F |");
387ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
388ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
389ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
390ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Emoji modifier + variation selector
391ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F466 U+1F3FB U+FE0F |");
392ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
393ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F466 |");
394ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
395ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
396ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
397ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Start withj ZERO WIDTH JOINER + regional indicator symbol
398ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D U+1F1FA |");
399ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
400ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+200D |");
401ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
402ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
403ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
404ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // ZERO WIDTH JOINER + Regional indicator symbol
405ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F469 U+200D U+1F1FA |");
406ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
407ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F469 U+200D |");
408ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
409ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F469 |");
410ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
411ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
412ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
413ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Regional indicator symbol + end with ZERO WIDTH JOINER
414ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA U+200D |");
415ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
416ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F1FA |");
417ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
418ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
419ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
420ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Regional indicator symbol + ZERO WIDTH JOINER
421ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA U+200D U+1F469 |");
422ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
423ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
424ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
425ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Start with ZERO WIDTH JOINER + emoji modifier
426ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+200D U+1F3FB |");
427ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
428ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+200D |");
429ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
430ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
431ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
432ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // ZERO WIDTH JOINER + emoji modifier
433ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F469 U+200D U+1F3FB |");
434ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
435ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F469 U+200D |");
436ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
437ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F469 |");
438ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
439ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
440ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
441ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Emoji modifier + end with ZERO WIDTH JOINER
442ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F466 U+1F3FB U+200D |");
443ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
444ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F466 U+1F3FB |");
445ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
446ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
447ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
448ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Emoji modifier + ZERO WIDTH JOINER
449ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F466 U+1F3FB U+200D U+1F469 |");
450ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
4513675d3cd84c446d05b3e3e97b04cf0427b2f5da6Seigo Nonaka        state.assertEquals("U+1F466 |");
452ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
453ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
454ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
455ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Regional indicator symbol + Emoji modifier
456ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F1FA U+1F3FB |");
457ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
458ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F1FA |");
459ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
460ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
461ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
462ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        // Emoji modifier + regional indicator symbol
463ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.setByString("U+1F466 U+1F3FB U+1F1FA |");
464ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
465ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("U+1F466 U+1F3FB |");
466ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        backspace(state, 0);
467ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        state.assertEquals("|");
468ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
469ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka}
470