1f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir/*
2f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * Copyright (C) 2017 The Android Open Source Project
3f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir *
4f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License");
5f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * you may not use this file except in compliance with the License.
6f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * You may obtain a copy of the License at
7f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir *
8f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir *      http://www.apache.org/licenses/LICENSE-2.0
9f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir *
10f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * Unless required by applicable law or agreed to in writing, software
11f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS,
12f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * See the License for the specific language governing permissions and
14f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * limitations under the License.
15f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir */
16f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirpackage android.support.text.emoji.widget;
17f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
18f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static junit.framework.Assert.assertSame;
19f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static junit.framework.TestCase.assertNotNull;
20f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
21f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.hamcrest.Matchers.arrayWithSize;
22f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.hamcrest.Matchers.instanceOf;
23f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.junit.Assert.assertEquals;
24f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.junit.Assert.assertThat;
25f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Matchers.any;
26f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Matchers.anyInt;
27f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Matchers.anyObject;
28f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Matchers.same;
29f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Mockito.mock;
30f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Mockito.never;
31f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Mockito.reset;
32f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Mockito.times;
33f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Mockito.verify;
34f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Mockito.withSettings;
35f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
36f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.support.test.filters.SmallTest;
37f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.support.test.runner.AndroidJUnit4;
38f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.support.text.emoji.EmojiSpan;
39f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.Editable;
40f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.SpanWatcher;
41f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.Spannable;
42f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.Spanned;
43f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.TextWatcher;
44f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.style.QuoteSpan;
45f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
46f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport junit.framework.Assert;
47f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
48f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport org.junit.Before;
49f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport org.junit.Test;
50f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport org.junit.runner.RunWith;
51f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
52f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir@SmallTest
53f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir@RunWith(AndroidJUnit4.class)
54f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirpublic class SpannableBuilderTest {
55f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
56f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    private TextWatcher mWatcher;
57f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    private Class mClass;
58f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
59f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Before
60f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void setup() {
61f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        mWatcher = mock(TextWatcher.class, withSettings().extraInterfaces(SpanWatcher.class));
62f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        mClass = mWatcher.getClass();
63f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
64f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
65f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
66f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testConstructor() {
67f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        new SpannableBuilder(mClass);
68f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
69f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        new SpannableBuilder(mClass, "abc");
70f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
71f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        new SpannableBuilder(mClass, "abc", 0, 3);
72f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
73f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // test spannable copying? do I need it?
74f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
75f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
76f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
77f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testSubSequence() {
78f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abc");
79f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final QuoteSpan span1 = mock(QuoteSpan.class);
80f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final QuoteSpan span2 = mock(QuoteSpan.class);
81f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(span1, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
82f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(span2, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
83f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
84f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final CharSequence subsequence = spannable.subSequence(0, 1);
85f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertNotNull(subsequence);
86f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(subsequence, instanceOf(SpannableBuilder.class));
87f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
88f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final QuoteSpan[] spans = spannable.getSpans(0, 1, QuoteSpan.class);
89f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(spans, arrayWithSize(1));
90f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertSame(spans[0], span1);
91f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
92f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
93f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
94f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testSetAndGetSpan() {
95f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abcde");
96f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(mWatcher, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
97f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
98f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // getSpans should return the span
99f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        Object[] spans = spannable.getSpans(0, spannable.length(), mClass);
100f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertNotNull(spans);
101f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(spans, arrayWithSize(1));
102f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertSame(mWatcher, spans[0]);
103f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
104f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // span attributes should be correct
105f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertEquals(1, spannable.getSpanStart(mWatcher));
106f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertEquals(2, spannable.getSpanEnd(mWatcher));
107f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spannable.getSpanFlags(mWatcher));
108f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
109f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // should remove the span
110f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.removeSpan(mWatcher);
111f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spans = spannable.getSpans(0, spannable.length(), QuoteSpan.class);
112f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertNotNull(spans);
113f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(spans, arrayWithSize(0));
114f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
115f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
116f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
117f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testNextSpanTransition() {
118f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpannableBuilder spannable = new SpannableBuilder(mClass, "abcde");
119f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(mWatcher, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
120f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final int start = spannable.nextSpanTransition(0, spannable.length(), mClass);
121f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        Assert.assertEquals(1, start);
122f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
123f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
124f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
125f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testBlocksSpanCallbacks_forEmojiSpans() {
126f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final EmojiSpan span = mock(EmojiSpan.class);
127f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
128f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(mWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
129f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
130f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        reset(mWatcher);
131f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
132f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.delete(0, 3);
133f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
134f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify that characters are deleted
135f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertEquals("456", spannable.toString());
136f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify EmojiSpan is deleted
137f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);
138f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(spans, arrayWithSize(0));
139f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
140f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify the call to span callbacks are blocked
141f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify((SpanWatcher) mWatcher, never()).onSpanRemoved(any(Spannable.class),
142f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                same(span), anyInt(), anyInt());
143f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify((SpanWatcher) mWatcher, never()).onSpanAdded(any(Spannable.class),
144f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                same(span), anyInt(), anyInt());
145f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify((SpanWatcher) mWatcher, never()).onSpanChanged(any(Spannable.class),
146f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                same(span), anyInt(), anyInt(), anyInt(), anyInt());
147f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
148f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify the call to TextWatcher callbacks are called
149f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(mWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(),
150f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt(), anyInt());
151f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(mWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
152f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt());
153f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
154f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
155f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
156f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
157f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testDoesNotBlockSpanCallbacks_forNonEmojiSpans() {
158f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final QuoteSpan span = mock(QuoteSpan.class);
159f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
160f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(mWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
161f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
162f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        reset(mWatcher);
163f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
164f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.delete(0, 3);
165f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
166f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify that characters are deleted
167f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertEquals("456", spannable.toString());
168f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify QuoteSpan is deleted
169f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        QuoteSpan[] spans = spannable.getSpans(0, spannable.length(), QuoteSpan.class);
170f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(spans, arrayWithSize(0));
171f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
172f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify the call to span callbacks are not blocked
173f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify((SpanWatcher) mWatcher, times(1)).onSpanRemoved(any(Spannable.class),
174f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyObject(), anyInt(), anyInt());
175f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
176f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify the call to TextWatcher callbacks are called
177f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(mWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(), anyInt(),
178f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt());
179f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(mWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
180f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt());
181f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(mWatcher, times(1)).afterTextChanged(any(Editable.class));
182f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
183f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
184f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    @Test
185f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public void testDoesNotBlockSpanCallbacksForOtherWatchers() {
186f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final TextWatcher textWatcher = mock(TextWatcher.class);
187f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpanWatcher spanWatcher = mock(SpanWatcher.class);
188f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
189f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final EmojiSpan span = mock(EmojiSpan.class);
190f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        final SpannableBuilder spannable = new SpannableBuilder(mClass, "123456");
191f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(textWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
192f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(spanWatcher, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
193f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.setSpan(span, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
194f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        reset(textWatcher);
195f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
196f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        spannable.delete(0, 3);
197f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
198f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify that characters are deleted
199f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertEquals("456", spannable.toString());
200f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify EmojiSpan is deleted
201f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);
202f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        assertThat(spans, arrayWithSize(0));
203f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
204f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify the call to span callbacks are blocked
205f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(spanWatcher, times(1)).onSpanRemoved(any(Spannable.class), same(span),
206f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt(), anyInt());
207f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
208f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        // verify the call to TextWatcher callbacks are called
209f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(textWatcher, times(1)).beforeTextChanged(any(CharSequence.class), anyInt(),
210f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt(), anyInt());
211f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(textWatcher, times(1)).onTextChanged(any(CharSequence.class), anyInt(), anyInt(),
212f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                anyInt());
213f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        verify(textWatcher, times(1)).afterTextChanged(any(Editable.class));
214f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
215f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir}
216