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
17package com.android.inputmethod.latin.utils;
18
19import android.test.AndroidTestCase;
20import android.test.suitebuilder.annotation.SmallTest;
21import android.text.style.SuggestionSpan;
22import android.text.style.URLSpan;
23import android.text.SpannableString;
24import android.text.SpannableStringBuilder;
25import android.text.Spanned;
26import android.text.SpannedString;
27
28@SmallTest
29public class SpannableStringUtilsTests extends AndroidTestCase {
30    public void testConcatWithSuggestionSpansOnly() {
31        SpannableStringBuilder s = new SpannableStringBuilder("test string\ntest string\n"
32                + "test string\ntest string\ntest string\ntest string\ntest string\ntest string\n"
33                + "test string\ntest string\n");
34        final int N = 10;
35        for (int i = 0; i < N; ++i) {
36            // Put a PARAGRAPH-flagged span that should not be found in the result.
37            s.setSpan(new SuggestionSpan(getContext(),
38                    new String[] {"" + i}, Spanned.SPAN_PARAGRAPH),
39                    i * 12, i * 12 + 12, Spanned.SPAN_PARAGRAPH);
40            // Put a normal suggestion span that should be found in the result.
41            s.setSpan(new SuggestionSpan(getContext(), new String[] {"" + i}, 0), i, i * 2, 0);
42            // Put a URL span than should not be found in the result.
43            s.setSpan(new URLSpan("http://a"), i, i * 2, 0);
44        }
45
46        final CharSequence a = s.subSequence(0, 15);
47        final CharSequence b = s.subSequence(15, s.length());
48        final Spanned result =
49                (Spanned)SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(a, b);
50
51        Object[] spans = result.getSpans(0, result.length(), SuggestionSpan.class);
52        for (int i = 0; i < spans.length; i++) {
53            final int flags = result.getSpanFlags(spans[i]);
54            assertEquals("Should not find a span with PARAGRAPH flag",
55                    flags & Spanned.SPAN_PARAGRAPH, 0);
56            assertTrue("Should be a SuggestionSpan", spans[i] instanceof SuggestionSpan);
57        }
58    }
59
60    private static void assertSpanCount(final int expectedCount, final CharSequence cs) {
61        final int actualCount;
62        if (cs instanceof Spanned) {
63            final Spanned spanned = (Spanned) cs;
64            actualCount = spanned.getSpans(0, spanned.length(), Object.class).length;
65        } else {
66            actualCount = 0;
67        }
68        assertEquals(expectedCount, actualCount);
69    }
70
71    private static void assertSpan(final CharSequence cs, final Object expectedSpan,
72            final int expectedStart, final int expectedEnd, final int expectedFlags) {
73        assertTrue(cs instanceof Spanned);
74        final Spanned spanned = (Spanned) cs;
75        final Object[] actualSpans = spanned.getSpans(0, spanned.length(), Object.class);
76        for (Object actualSpan : actualSpans) {
77            if (actualSpan == expectedSpan) {
78                final int actualStart = spanned.getSpanStart(actualSpan);
79                final int actualEnd = spanned.getSpanEnd(actualSpan);
80                final int actualFlags = spanned.getSpanFlags(actualSpan);
81                assertEquals(expectedStart, actualStart);
82                assertEquals(expectedEnd, actualEnd);
83                assertEquals(expectedFlags, actualFlags);
84                return;
85            }
86        }
87        assertTrue(false);
88    }
89
90    public void testSplitCharSequenceWithSpan() {
91        // text:  " a bcd efg hij  "
92        // span1:  ^^^^^^^
93        // span2:  ^^^^^
94        // span3:              ^
95        final SpannableString spannableString = new SpannableString(" a bcd efg hij  ");
96        final Object span1 = new Object();
97        final Object span2 = new Object();
98        final Object span3 = new Object();
99        final int SPAN1_FLAGS = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
100        final int SPAN2_FLAGS = Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
101        final int SPAN3_FLAGS = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
102        spannableString.setSpan(span1, 0, 7, SPAN1_FLAGS);
103        spannableString.setSpan(span2, 0, 5, SPAN2_FLAGS);
104        spannableString.setSpan(span3, 12, 13, SPAN3_FLAGS);
105        final CharSequence[] charSequencesFromSpanned = SpannableStringUtils.split(
106                spannableString, " ", true /* preserveTrailingEmptySegmengs */);
107        final CharSequence[] charSequencesFromString = SpannableStringUtils.split(
108                spannableString.toString(), " ", true /* preserveTrailingEmptySegmengs */);
109
110
111        assertEquals(7, charSequencesFromString.length);
112        assertEquals(7, charSequencesFromSpanned.length);
113
114        // text:  ""
115        // span1: ^
116        // span2: ^
117        // span3:
118        assertEquals("", charSequencesFromString[0].toString());
119        assertSpanCount(0, charSequencesFromString[0]);
120        assertEquals("", charSequencesFromSpanned[0].toString());
121        assertSpanCount(2, charSequencesFromSpanned[0]);
122        assertSpan(charSequencesFromSpanned[0], span1, 0, 0, SPAN1_FLAGS);
123        assertSpan(charSequencesFromSpanned[0], span2, 0, 0, SPAN2_FLAGS);
124
125        // text:  "a"
126        // span1:  ^
127        // span2:  ^
128        // span3:
129        assertEquals("a", charSequencesFromString[1].toString());
130        assertSpanCount(0, charSequencesFromString[1]);
131        assertEquals("a", charSequencesFromSpanned[1].toString());
132        assertSpanCount(2, charSequencesFromSpanned[1]);
133        assertSpan(charSequencesFromSpanned[1], span1, 0, 1, SPAN1_FLAGS);
134        assertSpan(charSequencesFromSpanned[1], span2, 0, 1, SPAN2_FLAGS);
135
136        // text:  "bcd"
137        // span1:  ^^^
138        // span2:  ^^
139        // span3:
140        assertEquals("bcd", charSequencesFromString[2].toString());
141        assertSpanCount(0, charSequencesFromString[2]);
142        assertEquals("bcd", charSequencesFromSpanned[2].toString());
143        assertSpanCount(2, charSequencesFromSpanned[2]);
144        assertSpan(charSequencesFromSpanned[2], span1, 0, 3, SPAN1_FLAGS);
145        assertSpan(charSequencesFromSpanned[2], span2, 0, 2, SPAN2_FLAGS);
146
147        // text:  "efg"
148        // span1:
149        // span2:
150        // span3:
151        assertEquals("efg", charSequencesFromString[3].toString());
152        assertSpanCount(0, charSequencesFromString[3]);
153        assertEquals("efg", charSequencesFromSpanned[3].toString());
154        assertSpanCount(0, charSequencesFromSpanned[3]);
155
156        // text:  "hij"
157        // span1:
158        // span2:
159        // span3:   ^
160        assertEquals("hij", charSequencesFromString[4].toString());
161        assertSpanCount(0, charSequencesFromString[4]);
162        assertEquals("hij", charSequencesFromSpanned[4].toString());
163        assertSpanCount(1, charSequencesFromSpanned[4]);
164        assertSpan(charSequencesFromSpanned[4], span3, 1, 2, SPAN3_FLAGS);
165
166        // text:  ""
167        // span1:
168        // span2:
169        // span3:
170        assertEquals("", charSequencesFromString[5].toString());
171        assertSpanCount(0, charSequencesFromString[5]);
172        assertEquals("", charSequencesFromSpanned[5].toString());
173        assertSpanCount(0, charSequencesFromSpanned[5]);
174
175        // text:  ""
176        // span1:
177        // span2:
178        // span3:
179        assertEquals("", charSequencesFromString[6].toString());
180        assertSpanCount(0, charSequencesFromString[6]);
181        assertEquals("", charSequencesFromSpanned[6].toString());
182        assertSpanCount(0, charSequencesFromSpanned[6]);
183    }
184
185    public void testSplitCharSequencePreserveTrailingEmptySegmengs() {
186        assertEquals(1, SpannableStringUtils.split("", " ",
187                false /* preserveTrailingEmptySegmengs */).length);
188        assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ",
189                false /* preserveTrailingEmptySegmengs */).length);
190
191        assertEquals(1, SpannableStringUtils.split("", " ",
192                true /* preserveTrailingEmptySegmengs */).length);
193        assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ",
194                true /* preserveTrailingEmptySegmengs */).length);
195
196        assertEquals(0, SpannableStringUtils.split(" ", " ",
197                false /* preserveTrailingEmptySegmengs */).length);
198        assertEquals(0, SpannableStringUtils.split(new SpannedString(" "), " ",
199                false /* preserveTrailingEmptySegmengs */).length);
200
201        assertEquals(2, SpannableStringUtils.split(" ", " ",
202                true /* preserveTrailingEmptySegmengs */).length);
203        assertEquals(2, SpannableStringUtils.split(new SpannedString(" "), " ",
204                true /* preserveTrailingEmptySegmengs */).length);
205
206        assertEquals(3, SpannableStringUtils.split("a b c  ", " ",
207                false /* preserveTrailingEmptySegmengs */).length);
208        assertEquals(3, SpannableStringUtils.split(new SpannedString("a b c  "), " ",
209                false /* preserveTrailingEmptySegmengs */).length);
210
211        assertEquals(5, SpannableStringUtils.split("a b c  ", " ",
212                true /* preserveTrailingEmptySegmengs */).length);
213        assertEquals(5, SpannableStringUtils.split(new SpannedString("a b c  "), " ",
214                true /* preserveTrailingEmptySegmengs */).length);
215
216        assertEquals(6, SpannableStringUtils.split("a     b ", " ",
217                false /* preserveTrailingEmptySegmengs */).length);
218        assertEquals(6, SpannableStringUtils.split(new SpannedString("a     b "), " ",
219                false /* preserveTrailingEmptySegmengs */).length);
220
221        assertEquals(7, SpannableStringUtils.split("a     b ", " ",
222                true /* preserveTrailingEmptySegmengs */).length);
223        assertEquals(7, SpannableStringUtils.split(new SpannedString("a     b "), " ",
224                true /* preserveTrailingEmptySegmengs */).length);
225    }
226}
227