1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.inputmethod.latin;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 
23 import androidx.test.filters.SmallTest;
24 import androidx.test.runner.AndroidJUnit4;
25 
26 import com.android.inputmethod.latin.common.Constants;
27 import com.android.inputmethod.latin.common.CoordinateUtils;
28 import com.android.inputmethod.latin.common.StringUtils;
29 
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 
33 /**
34  * Unit tests for WordComposer.
35  */
36 @SmallTest
37 @RunWith(AndroidJUnit4.class)
38 public class WordComposerTests {
39 
40     @Test
testMoveCursor()41     public void testMoveCursor() {
42         final WordComposer wc = new WordComposer();
43         // BMP is the Basic Multilingual Plane, as defined by Unicode. This includes
44         // most characters for most scripts, including all Roman alphabet languages,
45         // CJK, Arabic, Hebrew. Notable exceptions include some emoji and some
46         // very rare Chinese ideograms. BMP characters can be encoded on 2 bytes
47         // in UTF-16, whereas those outside the BMP need 4 bytes.
48         // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
49         final String STR_WITHIN_BMP = "abcdef";
50         final int[] CODEPOINTS_WITHIN_BMP = StringUtils.toCodePointArray(STR_WITHIN_BMP);
51         final int[] COORDINATES_WITHIN_BMP =
52                 CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length,
53                         Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
54         wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP);
55         assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length()));
56         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
57         wc.setCursorPositionWithinWord(2);
58         assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
59         // Move the cursor to after the 'd'
60         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(2));
61         assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
62         // Move the cursor to after the 'e'
63         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
64         assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
65         assertEquals(wc.size(), 6);
66         // Move the cursor to after the 'f'
67         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
68         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
69         // Move the cursor past the end of the word
70         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1));
71         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15));
72         // Do what LatinIME does when the cursor is moved outside of the word,
73         // and check the behavior is correct.
74         wc.reset();
75 
76         // \uD861\uDED7 is ��, a character outside the BMP
77         final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh";
78         final int[] CODEPOINTS_WITH_SUPPLEMENTARY_CHAR =
79                 StringUtils.toCodePointArray(STR_WITH_SUPPLEMENTARY_CHAR);
80         final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR =
81                 CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length,
82                         Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
83         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
84                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
85         assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length);
86         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
87         wc.setCursorPositionWithinWord(3);
88         assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
89         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(6));
90         assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
91         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
92         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
93 
94         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
95                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
96         wc.setCursorPositionWithinWord(3);
97         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
98 
99         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
100                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
101         wc.setCursorPositionWithinWord(3);
102         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
103 
104         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
105                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
106         wc.setCursorPositionWithinWord(3);
107         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3));
108         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1));
109 
110 
111         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
112                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
113         wc.setCursorPositionWithinWord(3);
114         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9));
115 
116         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
117                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
118         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10));
119 
120         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
121                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
122         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11));
123 
124         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
125                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
126         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
127 
128         wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
129                 COORDINATES_WITH_SUPPLEMENTARY_CHAR);
130         wc.setCursorPositionWithinWord(2);
131         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
132     }
133 }
134