New WordIterator tests

Plus tests for surrogate characters in ArrowKeyMovement.

Change-Id: I954900e9776d6e365db32cf7c4e436ebeca1fb35
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index 76f28cc..ba2bcdd 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -1185,17 +1185,38 @@
         initTextViewWithNullLayout("before word after");
         checkMoveFromInsideWord(7, 10);
 
-        // Surrogate characters are not (yet) correctly supported. TODO
-        //final String ANGRY_FACE_EMOJI = "\uDBB8\uDF20";
-        //initTextViewWithNullLayout("before " + ANGRY_FACE_EMOJI + " after");
-        //checkMoveFromInsideWord(7, 9);
+        // Surrogate characters: bairkan should be considered as a standard letter
+        final String BAIRKAN = "\uD800\uDF31";
 
+        initTextViewWithNullLayout("before wo" + BAIRKAN + "rd after");
+        checkMoveFromInsideWord(7, 12);
+
+        initTextViewWithNullLayout("before " + BAIRKAN + BAIRKAN + "xx after");
+        checkMoveFromInsideWord(7, 12);
+
+        initTextViewWithNullLayout("before xx" + BAIRKAN + BAIRKAN + " after");
+        checkMoveFromInsideWord(7, 12);
+
+        initTextViewWithNullLayout("before x" + BAIRKAN + "x" + BAIRKAN + " after");
+        checkMoveFromInsideWord(7, 12);
+
+        initTextViewWithNullLayout("before " + BAIRKAN + "x" + BAIRKAN + "x after");
+        checkMoveFromInsideWord(7, 12);
+
+        initTextViewWithNullLayout("before " + BAIRKAN + BAIRKAN + BAIRKAN + " after");
+        checkMoveFromInsideWord(7, 12);
     }
 
     private void checkMoveFromInsideWord(int wordStart, int wordEnd) {
 
+        CharSequence text = mTextView.getText();
+
         // Check following always goes at the end of the word
         for (int offset = wordStart; offset != wordEnd + 1; offset++) {
+            // Skip positions located between a pair of surrogate characters
+            if (Character.isSurrogatePair(text.charAt(offset - 1), text.charAt(offset))) {
+                continue;
+            }
             Selection.setSelection(mEditable, offset);
             assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
             assertSelection(wordEnd + 1);
@@ -1203,6 +1224,9 @@
 
         // Check preceding always goes at the beginning of the word
         for (int offset = wordEnd + 1; offset != wordStart; offset--) {
+            if (Character.isSurrogatePair(text.charAt(offset - 1), text.charAt(offset))) {
+                continue;
+            }
             Selection.setSelection(mEditable, offset);
             assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
             assertSelection(wordStart);
diff --git a/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java b/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java
new file mode 100644
index 0000000..2b1f461
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.method.cts;
+
+import android.text.method.WordIterator;
+
+import java.text.BreakIterator;
+
+import junit.framework.TestCase;
+
+public class WordIteratorTest extends TestCase {
+
+    WordIterator wi = new WordIterator();
+
+    private void checkIsWordWithSurrogate(int beginning, int end, int surrogateIndex) {
+        for (int i = beginning; i <= end; i++) {
+            if (i == surrogateIndex) continue;
+            assertEquals(beginning, wi.getBeginning(i));
+            assertEquals(end, wi.getEnd(i));
+        }
+    }
+
+    private void checkIsWord(int beginning, int end) {
+        checkIsWordWithSurrogate(beginning, end, -1);
+    }
+
+    private void checkIsNotWord(int beginning, int end) {
+        for (int i = beginning; i <= end; i++) {
+            assertEquals(BreakIterator.DONE, wi.getBeginning(i));
+            assertEquals(BreakIterator.DONE, wi.getEnd(i));
+        }
+    }
+
+    public void testEmptyString() {
+        wi.setCharSequence("");
+        assertEquals(BreakIterator.DONE, wi.following(0));
+        assertEquals(BreakIterator.DONE, wi.preceding(0));
+
+        assertEquals(BreakIterator.DONE, wi.getBeginning(0));
+        assertEquals(BreakIterator.DONE, wi.getEnd(0));
+    }
+
+    public void testOneWord() {
+        wi.setCharSequence("I");
+        checkIsWord(0, 1);
+
+        wi.setCharSequence("am");
+        checkIsWord(0, 2);
+
+        wi.setCharSequence("zen");
+        checkIsWord(0, 3);
+    }
+
+    public void testSpacesOnly() {
+        wi.setCharSequence(" ");
+        checkIsNotWord(0, 1);
+
+        wi.setCharSequence(", ");
+        checkIsNotWord(0, 2);
+
+        wi.setCharSequence(":-)");
+        checkIsNotWord(0, 3);
+    }
+
+    public void testBeginningEnd() {
+        wi.setCharSequence("Well hello,   there! ");
+        //                  0123456789012345678901
+        checkIsWord(0, 4);
+        checkIsWord(5, 10);
+        checkIsNotWord(11, 13);
+        checkIsWord(14, 19);
+        checkIsNotWord(20, 21);
+
+        wi.setCharSequence("  Another - sentence");
+        //                  012345678901234567890
+        checkIsNotWord(0, 1);
+        checkIsWord(2, 9);
+        checkIsNotWord(10, 11);
+        checkIsWord(12, 20);
+
+        wi.setCharSequence("This is \u0644\u0627 tested"); // Lama-aleph
+        //                  012345678     9     01234567
+        checkIsWord(0, 4);
+        checkIsWord(5, 7);
+        checkIsWord(8, 10);
+        checkIsWord(11, 17);
+    }
+
+    public void testSurrogate() {
+        final String BAIRKAN = "\uD800\uDF31";
+
+        wi.setCharSequence("one we" + BAIRKAN + "ird word");
+        //                  012345    67         890123456
+
+        checkIsWord(0, 3);
+        // Skip index 7 (there is no point in starting between the two surrogate characters)
+        checkIsWordWithSurrogate(4, 11, 7);
+        checkIsWord(12, 16);
+
+        wi.setCharSequence("one " + BAIRKAN + "xxx word");
+        //                  0123    45         678901234
+
+        checkIsWord(0, 3);
+        checkIsWordWithSurrogate(4, 9, 5);
+        checkIsWord(10, 14);
+
+        wi.setCharSequence("one xxx" + BAIRKAN + " word");
+        //                  0123456    78         901234
+
+        checkIsWord(0, 3);
+        checkIsWordWithSurrogate(4, 9, 8);
+        checkIsWord(10, 14);
+    }
+}