1/*
2 * Copyright (C) 2008 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 android.text;
18
19import static org.junit.Assert.assertEquals;
20
21import android.graphics.Typeface;
22import android.os.Parcel;
23import android.support.test.filters.SmallTest;
24import android.support.test.runner.AndroidJUnit4;
25import android.text.style.CharacterStyle;
26import android.text.style.StyleSpan;
27import android.text.style.TextAppearanceSpan;
28import android.text.style.TypefaceSpan;
29
30import org.junit.Test;
31import org.junit.runner.RunWith;
32
33/**
34 * SpannedTest tests some features of Spanned
35 */
36@SmallTest
37@RunWith(AndroidJUnit4.class)
38public class SpannedTest {
39    private int mExpect;
40
41    @Test
42    public void testSpannableString() {
43        checkPriority(new SpannableString("the quick brown fox"));
44    }
45
46    @Test
47    public void testSpannableStringBuilder() {
48        checkPriority2(new SpannableStringBuilder("the quick brown fox"));
49    }
50
51    @Test
52    public void testAppend() {
53        Object o = new Object();
54        SpannableString ss = new SpannableString("Test");
55        ss.setSpan(o, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
56
57        SpannableStringBuilder ssb = new SpannableStringBuilder();
58        ssb.append(ss);
59        assertEquals(0, ssb.getSpanStart(o));
60        assertEquals(4, ssb.getSpanEnd(o));
61        assertEquals(1, ssb.getSpans(0, 4, Object.class).length);
62
63        ssb.insert(0, ss);
64        assertEquals(4, ssb.getSpanStart(o));
65        assertEquals(8, ssb.getSpanEnd(o));
66        assertEquals(0, ssb.getSpans(0, 4, Object.class).length);
67        assertEquals(1, ssb.getSpans(4, 8, Object.class).length);
68    }
69
70    @Test
71    public void testWrapParcel() {
72        SpannableString s = new SpannableString("Hello there world");
73        CharacterStyle mark = new StyleSpan(Typeface.BOLD);
74        s.setSpan(mark, 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
75        s.setSpan(CharacterStyle.wrap(mark), 3, 7,
76                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
77        s.setSpan(new TextAppearanceSpan("mono", 0, -1, null, null), 7, 8,
78                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
79        s.setSpan(CharacterStyle.wrap(new TypefaceSpan("mono")), 8, 9,
80                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
81
82        Parcel p = Parcel.obtain();
83        TextUtils.writeToParcel(s, p, 0);
84        p.setDataPosition(0);
85
86        Spanned s2 = (Spanned) TextUtils.CHAR_SEQUENCE_CREATOR.
87                        createFromParcel(p);
88        StyleSpan[] style;
89
90        style = s2.getSpans(1, 2, StyleSpan.class);
91        assertEquals(1, style.length);
92        assertEquals(1, s2.getSpanStart(style[0]));
93        assertEquals(2, s2.getSpanEnd(style[0]));
94
95        style = s2.getSpans(3, 7, StyleSpan.class);
96        assertEquals(1, style.length);
97        assertEquals(3, s2.getSpanStart(style[0]));
98        assertEquals(7, s2.getSpanEnd(style[0]));
99
100        TextAppearanceSpan[] appearance = s2.getSpans(7, 8,
101                                                TextAppearanceSpan.class);
102        assertEquals(1, appearance.length);
103        assertEquals(7, s2.getSpanStart(appearance[0]));
104        assertEquals(8, s2.getSpanEnd(appearance[0]));
105
106        TypefaceSpan[] tf = s2.getSpans(8, 9, TypefaceSpan.class);
107        assertEquals(1, tf.length);
108        assertEquals(8, s2.getSpanStart(tf[0]));
109        assertEquals(9, s2.getSpanEnd(tf[0]));
110    }
111
112    private void checkPriority(Spannable s) {
113        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
114                                      (5 << Spannable.SPAN_PRIORITY_SHIFT));
115        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
116                                      (10 << Spannable.SPAN_PRIORITY_SHIFT));
117        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
118                                      (0 << Spannable.SPAN_PRIORITY_SHIFT));
119        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
120                                      (15 << Spannable.SPAN_PRIORITY_SHIFT));
121        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
122                                      (3 << Spannable.SPAN_PRIORITY_SHIFT));
123        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
124                                      (6 << Spannable.SPAN_PRIORITY_SHIFT));
125        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
126                                      (0 << Spannable.SPAN_PRIORITY_SHIFT));
127
128        Object[] spans = s.getSpans(0, s.length(), Object.class);
129
130        for (int i = 0; i < spans.length - 1; i++) {
131            assertEquals((s.getSpanFlags(spans[i]) & Spanned.SPAN_PRIORITY) >=
132                         (s.getSpanFlags(spans[i + 1]) & Spanned.SPAN_PRIORITY),
133                         true);
134        }
135
136        mExpect = 0;
137
138        s.setSpan(new Watcher(2), 0, s.length(),
139                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
140                  (2 << Spannable.SPAN_PRIORITY_SHIFT));
141        s.setSpan(new Watcher(4), 0, s.length(),
142                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
143                  (4 << Spannable.SPAN_PRIORITY_SHIFT));
144        s.setSpan(new Watcher(1), 0, s.length(),
145                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
146                  (1 << Spannable.SPAN_PRIORITY_SHIFT));
147        s.setSpan(new Watcher(3), 0, s.length(),
148                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
149                  (3 << Spannable.SPAN_PRIORITY_SHIFT));
150
151        mExpect = 4;
152        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
153        assertEquals(mExpect, 0);
154    }
155
156    private void checkPriority2(SpannableStringBuilder ssb) {
157        checkPriority(ssb);
158
159        mExpect = 4;
160        ssb.insert(3, "something");
161        assertEquals(mExpect, 0);
162    }
163
164    private class Watcher implements SpanWatcher, TextWatcher {
165        private int mSequence;
166
167        public Watcher(int sequence) {
168            mSequence = sequence;
169        }
170
171        @Override
172        public void onSpanChanged(Spannable b, Object o, int s, int e, int st, int en) { }
173
174        @Override
175        public void onSpanRemoved(Spannable b, Object o, int s, int e) { }
176
177        @Override
178        public void onSpanAdded(Spannable b, Object o, int s, int e) {
179            if (mExpect != 0) {
180                assertEquals(mSequence, mExpect);
181                mExpect = mSequence - 1;
182            }
183        }
184
185        @Override
186        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
187
188        @Override
189        public void onTextChanged(CharSequence s, int start, int before, int count) {
190            if (mExpect != 0) {
191                assertEquals(mSequence, mExpect);
192                mExpect = mSequence - 1;
193            }
194        }
195
196        @Override
197        public void afterTextChanged(Editable s) { }
198    }
199}
200