aboutsummaryrefslogtreecommitdiffstats
/*
 * Copyright (C) 2013 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 org.kelar.inputmethod.latin.utils;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.content.Context;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.style.SuggestionSpan;
import android.text.style.URLSpan;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class SpannableStringUtilsTests {

    private Context getContext() {
        return InstrumentationRegistry.getTargetContext();
    }

    @Test
    public void testConcatWithSuggestionSpansOnly() {
        SpannableStringBuilder s = new SpannableStringBuilder("test string\ntest string\n"
                + "test string\ntest string\ntest string\ntest string\ntest string\ntest string\n"
                + "test string\ntest string\n");
        final int N = 10;
        for (int i = 0; i < N; ++i) {
            // Put a PARAGRAPH-flagged span that should not be found in the result.
            s.setSpan(new SuggestionSpan(getContext(),
                    new String[] {"" + i}, Spanned.SPAN_PARAGRAPH),
                    i * 12, i * 12 + 12, Spanned.SPAN_PARAGRAPH);
            // Put a normal suggestion span that should be found in the result.
            s.setSpan(new SuggestionSpan(getContext(), new String[] {"" + i}, 0), i, i * 2, 0);
            // Put a URL span than should not be found in the result.
            s.setSpan(new URLSpan("http://a"), i, i * 2, 0);
        }

        final CharSequence a = s.subSequence(0, 15);
        final CharSequence b = s.subSequence(15, s.length());
        final Spanned result =
                (Spanned)SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(a, b);

        Object[] spans = result.getSpans(0, result.length(), SuggestionSpan.class);
        for (int i = 0; i < spans.length; i++) {
            final int flags = result.getSpanFlags(spans[i]);
            assertEquals("Should not find a span with PARAGRAPH flag",
                    flags & Spanned.SPAN_PARAGRAPH, 0);
            assertTrue("Should be a SuggestionSpan", spans[i] instanceof SuggestionSpan);
        }
    }

    private static void assertSpanCount(final int expectedCount, final CharSequence cs) {
        final int actualCount;
        if (cs instanceof Spanned) {
            final Spanned spanned = (Spanned) cs;
            actualCount = spanned.getSpans(0, spanned.length(), Object.class).length;
        } else {
            actualCount = 0;
        }
        assertEquals(expectedCount, actualCount);
    }

    private static void assertSpan(final CharSequence cs, final Object expectedSpan,
            final int expectedStart, final int expectedEnd, final int expectedFlags) {
        assertTrue(cs instanceof Spanned);
        final Spanned spanned = (Spanned) cs;
        final Object[] actualSpans = spanned.getSpans(0, spanned.length(), Object.class);
        for (Object actualSpan : actualSpans) {
            if (actualSpan == expectedSpan) {
                final int actualStart = spanned.getSpanStart(actualSpan);
                final int actualEnd = spanned.getSpanEnd(actualSpan);
                final int actualFlags = spanned.getSpanFlags(actualSpan);
                assertEquals(expectedStart, actualStart);
                assertEquals(expectedEnd, actualEnd);
                assertEquals(expectedFlags, actualFlags);
                return;
            }
        }
        assertTrue(false);
    }

    @Test
    public void testSplitCharSequenceWithSpan() {
        // text:  " a bcd efg hij  "
        // span1:  ^^^^^^^
        // span2:  ^^^^^
        // span3:              ^
        final SpannableString spannableString = new SpannableString(" a bcd efg hij  ");
        final Object span1 = new Object();
        final Object span2 = new Object();
        final Object span3 = new Object();
        final int SPAN1_FLAGS = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
        final int SPAN2_FLAGS = Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
        final int SPAN3_FLAGS = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
        spannableString.setSpan(span1, 0, 7, SPAN1_FLAGS);
        spannableString.setSpan(span2, 0, 5, SPAN2_FLAGS);
        spannableString.setSpan(span3, 12, 13, SPAN3_FLAGS);
        final CharSequence[] charSequencesFromSpanned = SpannableStringUtils.split(
                spannableString, " ", true /* preserveTrailingEmptySegmengs */);
        final CharSequence[] charSequencesFromString = SpannableStringUtils.split(
                spannableString.toString(), " ", true /* preserveTrailingEmptySegmengs */);


        assertEquals(7, charSequencesFromString.length);
        assertEquals(7, charSequencesFromSpanned.length);

        // text:  ""
        // span1: ^
        // span2: ^
        // span3:
        assertEquals("", charSequencesFromString[0].toString());
        assertSpanCount(0, charSequencesFromString[0]);
        assertEquals("", charSequencesFromSpanned[0].toString());
        assertSpanCount(2, charSequencesFromSpanned[0]);
        assertSpan(charSequencesFromSpanned[0], span1, 0, 0, SPAN1_FLAGS);
        assertSpan(charSequencesFromSpanned[0], span2, 0, 0, SPAN2_FLAGS);

        // text:  "a"
        // span1:  ^
        // span2:  ^
        // span3:
        assertEquals("a", charSequencesFromString[1].toString());
        assertSpanCount(0, charSequencesFromString[1]);
        assertEquals("a", charSequencesFromSpanned[1].toString());
        assertSpanCount(2, charSequencesFromSpanned[1]);
        assertSpan(charSequencesFromSpanned[1], span1, 0, 1, SPAN1_FLAGS);
        assertSpan(charSequencesFromSpanned[1], span2, 0, 1, SPAN2_FLAGS);

        // text:  "bcd"
        // span1:  ^^^
        // span2:  ^^
        // span3:
        assertEquals("bcd", charSequencesFromString[2].toString());
        assertSpanCount(0, charSequencesFromString[2]);
        assertEquals("bcd", charSequencesFromSpanned[2].toString());
        assertSpanCount(2, charSequencesFromSpanned[2]);
        assertSpan(charSequencesFromSpanned[2], span1, 0, 3, SPAN1_FLAGS);
        assertSpan(charSequencesFromSpanned[2], span2, 0, 2, SPAN2_FLAGS);

        // text:  "efg"
        // span1:
        // span2:
        // span3:
        assertEquals("efg", charSequencesFromString[3].toString());
        assertSpanCount(0, charSequencesFromString[3]);
        assertEquals("efg", charSequencesFromSpanned[3].toString());
        assertSpanCount(0, charSequencesFromSpanned[3]);

        // text:  "hij"
        // span1:
        // span2:
        // span3:   ^
        assertEquals("hij", charSequencesFromString[4].toString());
        assertSpanCount(0, charSequencesFromString[4]);
        assertEquals("hij", charSequencesFromSpanned[4].toString());
        assertSpanCount(1, charSequencesFromSpanned[4]);
        assertSpan(charSequencesFromSpanned[4], span3, 1, 2, SPAN3_FLAGS);

        // text:  ""
        // span1:
        // span2:
        // span3:
        assertEquals("", charSequencesFromString[5].toString());
        assertSpanCount(0, charSequencesFromString[5]);
        assertEquals("", charSequencesFromSpanned[5].toString());
        assertSpanCount(0, charSequencesFromSpanned[5]);

        // text:  ""
        // span1:
        // span2:
        // span3:
        assertEquals("", charSequencesFromString[6].toString());
        assertSpanCount(0, charSequencesFromString[6]);
        assertEquals("", charSequencesFromSpanned[6].toString());
        assertSpanCount(0, charSequencesFromSpanned[6]);
    }

    @Test
    public void testSplitCharSequencePreserveTrailingEmptySegmengs() {
        assertEquals(1, SpannableStringUtils.split("", " ",
                false /* preserveTrailingEmptySegmengs */).length);
        assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ",
                false /* preserveTrailingEmptySegmengs */).length);

        assertEquals(1, SpannableStringUtils.split("", " ",
                true /* preserveTrailingEmptySegmengs */).length);
        assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ",
                true /* preserveTrailingEmptySegmengs */).length);

        assertEquals(0, SpannableStringUtils.split(" ", " ",
                false /* preserveTrailingEmptySegmengs */).length);
        assertEquals(0, SpannableStringUtils.split(new SpannedString(" "), " ",
                false /* preserveTrailingEmptySegmengs */).length);

        assertEquals(2, SpannableStringUtils.split(" ", " ",
                true /* preserveTrailingEmptySegmengs */).length);
        assertEquals(2, SpannableStringUtils.split(new SpannedString(" "), " ",
                true /* preserveTrailingEmptySegmengs */).length);

        assertEquals(3, SpannableStringUtils.split("a b c  ", " ",
                false /* preserveTrailingEmptySegmengs */).length);
        assertEquals(3, SpannableStringUtils.split(new SpannedString("a b c  "), " ",
                false /* preserveTrailingEmptySegmengs */).length);

        assertEquals(5, SpannableStringUtils.split("a b c  ", " ",
                true /* preserveTrailingEmptySegmengs */).length);
        assertEquals(5, SpannableStringUtils.split(new SpannedString("a b c  "), " ",
                true /* preserveTrailingEmptySegmengs */).length);

        assertEquals(6, SpannableStringUtils.split("a     b ", " ",
                false /* preserveTrailingEmptySegmengs */).length);
        assertEquals(6, SpannableStringUtils.split(new SpannedString("a     b "), " ",
                false /* preserveTrailingEmptySegmengs */).length);

        assertEquals(7, SpannableStringUtils.split("a     b ", " ",
                true /* preserveTrailingEmptySegmengs */).length);
        assertEquals(7, SpannableStringUtils.split(new SpannedString("a     b "), " ",
                true /* preserveTrailingEmptySegmengs */).length);
    }
}