123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka/*
223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Copyright (C) 2016 The Android Open Source Project
323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka *
423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * you may not use this file except in compliance with the License.
623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * You may obtain a copy of the License at
723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka *
823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka *
1023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Unless required by applicable law or agreed to in writing, software
1123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
1223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * See the License for the specific language governing permissions and
1423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * limitations under the License.
1523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka */
1623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
1723a67678e3848e2465518769236139e6cafac2eeSeigo Nonakapackage android.text.method;
1823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
1923a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.app.Activity;
2023a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.test.suitebuilder.annotation.SmallTest;
2123a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.test.suitebuilder.annotation.Suppress;
2223a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.text.InputType;
2323a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.text.method.BaseKeyListener;
2423a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.text.method.KeyListenerTestCase;
2523a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.view.KeyEvent;
2623a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.widget.EditText;
2723a67678e3848e2465518769236139e6cafac2eeSeigo Nonakaimport android.widget.TextView.BufferType;
2823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
2923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka/**
3023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka * Test forward delete key handling of  {@link android.text.method.BaseKeyListener}.
3123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka *
32132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * Only contains edge cases. For normal cases, see {@see android.text.method.cts.ForwardDeleteTest}.
33132039ae89cfad501cd14fbb3819901151ae1890Seigo Nonaka * TODO: introduce test cases for surrogate pairs and replacement span.
3423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka */
3523a67678e3848e2465518769236139e6cafac2eeSeigo Nonakapublic class ForwardDeleteTest extends KeyListenerTestCase {
3623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
3723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        public int getInputType() {
3823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
3923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        }
4023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    };
4123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
4223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
4323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    // Then update the state to the result of TextView.
4423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    private void forwardDelete(final EditorState state, int modifiers) {
4523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        mActivity.runOnUiThread(new Runnable() {
4623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka            public void run() {
4723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka                mTextView.setText(state.mText, BufferType.EDITABLE);
4823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka                mTextView.setKeyListener(mKeyListener);
4923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka                mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
5023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka            }
5123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        });
5223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        mInstrumentation.waitForIdleSync();
5323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        assertTrue(mTextView.hasWindowFocus());
5423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
5523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
5623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        mActivity.runOnUiThread(new Runnable() {
5723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka            public void run() {
5823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka                mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
5923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka            }
6023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        });
6123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        mInstrumentation.waitForIdleSync();
6223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
6323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.mText = mTextView.getText();
6423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.mSelectionStart = mTextView.getSelectionStart();
6523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.mSelectionEnd = mTextView.getSelectionEnd();
6623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
6723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
6823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    @SmallTest
6923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    public void testCombiningEnclosingKeycaps() {
7023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        EditorState state = new EditorState();
7123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
7223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // multiple COMBINING ENCLOSING KEYCAP
7323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '1' U+20E3 U+20E3");
7423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
7523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
7623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
7723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated COMBINING ENCLOSING KEYCAP
7823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+20E3");
7923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
8023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
8123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
8223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated multiple COMBINING ENCLOSING KEYCAP
8323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+20E3 U+20E3");
8423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
8523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
8623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
8723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
8823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    @SmallTest
8923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    public void testVariationSelector() {
9023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        EditorState state = new EditorState();
9123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
9223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated variation selectors
9323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+FE0F");
9423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
9523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
9623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
9723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+E0100");
9823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
9923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
10023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
10123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated multiple variation selectors
10223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+FE0F U+FE0F");
10323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
10423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
10523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
10623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+FE0F U+E0100");
10723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
10823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
10923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
11023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+E0100 U+FE0F");
11123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
11223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
11323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
11423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+E0100 U+E0100");
11523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
11623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
11723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
11823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Multiple variation selectors
11923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '#' U+FE0F U+FE0F");
12023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
12123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
12223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
12323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '#' U+FE0F U+E0100");
12423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
12523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
12623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
12723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+845B U+E0100 U+FE0F");
12823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
12923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
13023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
13123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+845B U+E0100 U+E0100");
13223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
13323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
13423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
13523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
13623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    @SmallTest
13723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    public void testEmojiZeroWidthJoinerSequence() {
13823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        EditorState state = new EditorState();
13923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
140328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        // U+200D is ZERO WIDTH JOINER.
141328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("| U+1F441 U+200D U+1F5E8");
142328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        forwardDelete(state, 0);
143328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
144328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
145328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("| U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468");
146328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        forwardDelete(state, 0);
147328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
148328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
14923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // End with ZERO WIDTH JOINER
15023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F441 U+200D");
15123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
15223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
15323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
15423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Start with ZERO WIDTH JOINER
15523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D U+1F5E8");
15623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
15723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F5E8");
15823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
15923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
16023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
16123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Multiple ZERO WIDTH JOINER
16223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F441 U+200D U+200D U+1F5E8");
16323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
16423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F5E8");
16523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
16623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
16723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
16823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated ZERO WIDTH JOINER
16923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D");
17023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
17123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
17223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
17323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated multiple ZERO WIDTH JOINER
17423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D U+200D");
17523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
17623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
17723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
17823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
17923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    @SmallTest
18023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    public void testFlags() {
18123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        EditorState state = new EditorState();
18223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
18323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated regional indicator symbol
18423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA");
18523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
18623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
18723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
18823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Odd numbered regional indicator symbols
18923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA U+1F1F8 U+1F1FA");
19023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
19123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F1FA");
19223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
19323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
19423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
19523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
19623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    @SmallTest
19723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    public void testEmojiModifier() {
19823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        EditorState state = new EditorState();
19923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
200328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
201328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB");
202328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        forwardDelete(state, 0);
203328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka        state.assertEquals("|");
204328251a1d756463ad5f0dedcdf8a5b613387f8dcSeigo Nonaka
20523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated emoji modifier
20623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F3FB");
20723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
20823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
20923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
21023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Isolated multiple emoji modifier
21123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F3FB U+1F3FB");
21223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
21323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
21423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
21523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
21623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
21723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Multiple emoji modifiers
21823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB U+1F3FB");
21923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
22023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
22123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
22223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
22323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
22423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
22523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    @SmallTest
22623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    public void testMixedEdgeCases() {
22723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        EditorState state = new EditorState();
22823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
22923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // COMBINING ENCLOSING KEYCAP + variation selector
23023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '1' U+20E3 U+FE0F");
23123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
23223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
23323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
23423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Variation selector + COMBINING ENCLOSING KEYCAP
23523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+2665 U+FE0F U+20E3");
23623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
23723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
23823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
23923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
24023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '1' U+20E3 U+200D");
24123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
24223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
24323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
24423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
24523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '1' U+20E3 U+200D U+1F5E8");
24623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
24723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F5E8 ");
24823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
24923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
25023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D U+20E3");
25123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
25223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
25323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
25423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
25523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F441 U+200D U+20E3");
25623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
25723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
25823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
25923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // COMBINING ENCLOSING KEYCAP + regional indicator symbol
26023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '1' U+20E3 U+1F1FA");
26123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
26223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F1FA");
26323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
26423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
26523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
26623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
26723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA U+20E3");
26823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
26923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
27023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
27123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // COMBINING ENCLOSING KEYCAP + emoji modifier
27223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| '1' U+20E3 U+1F3FB");
27323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
27423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
27523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
27623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Emoji modifier + COMBINING ENCLOSING KEYCAP
27723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB U+20E3");
27823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
27923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
28023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
28123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Variation selector + end with ZERO WIDTH JOINER
28223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+2665 U+FE0F U+200D");
28323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
28423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
28523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
28623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Variation selector + ZERO WIDTH JOINER
28723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469");
28823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
28923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
29023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
29123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Start with ZERO WIDTH JOINER + variation selector
29223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D U+FE0F");
29323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
29423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
29523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
29623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // ZERO WIDTH JOINER + variation selector
29723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F469 U+200D U+FE0F");
29823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
29923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
30023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
30123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Variation selector + regional indicator symbol
30223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+2665 U+FE0F U+1F1FA");
30323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
30423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F1FA");
30523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
30623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
30723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
30823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Regional indicator symbol + variation selector
30923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA U+FE0F");
31023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
31123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
31223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
31323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Variation selector + emoji modifier
31423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+2665 U+FE0F U+1F3FB");
31523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
31623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
31723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
31823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Emoji modifier + variation selector
31923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB U+FE0F");
32023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
32123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
32223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
32323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Start with ZERO WIDTH JOINER + regional indicator symbol
32423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D U+1F1FA");
32523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
32623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F1FA");
32723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
32823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
32923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
33023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // ZERO WIDTH JOINER + regional indicator symbol
33123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F469 U+200D U+1F1FA");
33223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
33323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F1FA");
33423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
33523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Regional indicator symbol + end with ZERO WIDTH JOINER
33623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA U+200D");
33723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
33823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
33923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
34023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Regional indicator symbol + ZERO WIDTH JOINER
34123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA U+200D U+1F469");
34223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
34323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F469");
34423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
34523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
34623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
34723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Start with ZERO WIDTH JOINER + emoji modifier
34823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+200D U+1F3FB");
34923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
35023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
35123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
35223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // ZERO WIDTH JOINER + emoji modifier
35323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F469 U+200D U+1F3FB");
35423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
35523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
35623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
35723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Emoji modifier + end with ZERO WIDTH JOINER
35823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB U+200D");
35923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
36023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
36123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
36223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Emoji modifier + ZERO WIDTH JOINER
36323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
36423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
36523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F469");
36623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
36723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
36823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
36923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Regional indicator symbol + emoji modifier
37023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F1FA U+1F3FB");
37123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
37223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F3FB");
37323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
37423a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
37523a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka
37623a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        // Emoji modifier + regional indicator symbol
37723a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.setByString("| U+1F466 U+1F3FB U+1F1FA");
37823a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
37923a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("| U+1F1FA");
38023a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        forwardDelete(state, 0);
38123a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka        state.assertEquals("|");
38223a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka    }
38323a67678e3848e2465518769236139e6cafac2eeSeigo Nonaka}
384