/* * Copyright (C) 2018 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 androidx.textclassifier; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.os.Parcel; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ClickableSpan; import android.view.View; import androidx.annotation.Nullable; import androidx.collection.ArrayMap; import androidx.core.os.LocaleListCompat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; /** Instrumentation unit tests for {@link TextLinks}. */ @SmallTest @RunWith(AndroidJUnit4.class) public final class TextLinksTest { private static class NoOpSpan extends ClickableSpan { @Override public void onClick(View v) { // Do nothing. } } private static class CustomTextLinkSpan extends TextLinks.TextLinkSpan { CustomTextLinkSpan(@Nullable TextLinks.TextLink textLink) { super(textLink); } } private static class CustomSpanFactory implements TextLinks.SpanFactory { @Override public TextLinks.TextLinkSpan createSpan(TextLinks.TextLink textLink) { return new CustomTextLinkSpan(textLink); } } private TextClassifier mClassifier; private Map mDummyEntityScores; @Before public void setup() { mClassifier = new TextClassifier(); mDummyEntityScores = new ArrayMap<>(); mDummyEntityScores.put(TextClassifier.TYPE_ADDRESS, 0.2f); mDummyEntityScores.put(TextClassifier.TYPE_PHONE, 0.7f); mDummyEntityScores.put(TextClassifier.TYPE_OTHER, 0.3f); } private Map getEntityScores(float address, float phone, float other) { final Map result = new ArrayMap<>(); if (address > 0.f) { result.put(TextClassifier.TYPE_ADDRESS, address); } if (phone > 0.f) { result.put(TextClassifier.TYPE_PHONE, phone); } if (other > 0.f) { result.put(TextClassifier.TYPE_OTHER, other); } return result; } @Test public void testParcel() { final String fullText = "this is just a test"; final TextLinks reference = new TextLinks.Builder(fullText) .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f)) .addLink(5, 12, getEntityScores(.8f, .1f, .5f)) .build(); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); reference.writeToParcel(parcel, reference.describeContents()); parcel.setDataPosition(0); final TextLinks result = TextLinks.CREATOR.createFromParcel(parcel); final List resultList = new ArrayList<>(result.getLinks()); assertEquals(2, resultList.size()); assertEquals(0, resultList.get(0).getStart()); assertEquals(4, resultList.get(0).getEnd()); assertEquals(1, resultList.get(0).getEntityCount()); assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0)); assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f); assertEquals(5, resultList.get(1).getStart()); assertEquals(12, resultList.get(1).getEnd()); assertEquals(3, resultList.get(1).getEntityCount()); assertEquals(TextClassifier.TYPE_ADDRESS, resultList.get(1).getEntity(0)); assertEquals(TextClassifier.TYPE_OTHER, resultList.get(1).getEntity(1)); assertEquals(TextClassifier.TYPE_PHONE, resultList.get(1).getEntity(2)); assertEquals(.8f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f); assertEquals(.5f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f); assertEquals(.1f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f); } @Test public void testParcelOptions() { TextClassifier.EntityConfig entityConfig = new TextClassifier.EntityConfig( TextClassifier.ENTITY_PRESET_NONE); entityConfig.includeEntities("a", "b", "c"); entityConfig.excludeEntities("b"); final String callingPackageName = "packageName"; TextLinks.Options reference = new TextLinks.Options() .setDefaultLocales(LocaleListCompat.forLanguageTags("en-US,de-DE")) .setEntityConfig(entityConfig) .setApplyStrategy(TextLinks.APPLY_STRATEGY_REPLACE) .setSpanFactory(new CustomSpanFactory()) .setCallingPackageName(callingPackageName); final Parcel parcel = Parcel.obtain(); reference.writeToParcel(parcel, reference.describeContents()); parcel.setDataPosition(0); TextLinks.Options result = TextLinks.Options.CREATOR.createFromParcel(parcel); assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags()); assertEquals(Arrays.asList("a", "c"), result.getEntityConfig().getEntities(mClassifier)); assertEquals(TextLinks.APPLY_STRATEGY_REPLACE, result.getApplyStrategy()); assertEquals(null, result.getSpanFactory()); assertEquals(callingPackageName, result.getCallingPackageName()); } @Test public void testApplyDifferentText() { SpannableString text = new SpannableString("foo"); TextLinks links = new TextLinks.Builder("bar").build(); assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null), TextLinks.STATUS_DIFFERENT_TEXT); } @Test public void testApplyNoLinks() { SpannableString text = new SpannableString("foo"); TextLinks links = new TextLinks.Builder(text.toString()).build(); assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null), TextLinks.STATUS_NO_LINKS_FOUND); } @Test public void testApplyNoApplied() { SpannableString text = new SpannableString("foo"); text.setSpan(new NoOpSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); TextLinks links = new TextLinks.Builder(text.toString()).addLink( 0, 3, mDummyEntityScores).build(); assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, null), TextLinks.STATUS_NO_LINKS_APPLIED); } @Test public void testApplyAppliedDefaultSpanFactory() { SpannableString text = new SpannableString("foo"); TextLinks links = new TextLinks.Builder(text.toString()).addLink( 0, 3, mDummyEntityScores).build(); assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, null), TextLinks.STATUS_LINKS_APPLIED); TextLinks.TextLinkSpan[] spans = text.getSpans(0, 3, TextLinks.TextLinkSpan.class); assertEquals(spans.length, 1); assertTrue(links.getLinks().contains(spans[0].getTextLink())); } @Test public void testApplyAppliedDefaultSpanFactoryReplace() { SpannableString text = new SpannableString("foo"); text.setSpan(new NoOpSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); TextLinks links = new TextLinks.Builder(text.toString()).addLink( 0, 3, mDummyEntityScores).build(); assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null), TextLinks.STATUS_LINKS_APPLIED); TextLinks.TextLinkSpan[] spans = text.getSpans(0, 3, TextLinks.TextLinkSpan.class); assertEquals(spans.length, 1); assertTrue(links.getLinks().contains(spans[0].getTextLink())); } @Test public void testApplyAppliedCustomSpanFactory() { SpannableString text = new SpannableString("foo"); TextLinks links = new TextLinks.Builder(text.toString()).addLink( 0, 3, mDummyEntityScores).build(); assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, new CustomSpanFactory()), TextLinks.STATUS_LINKS_APPLIED); CustomTextLinkSpan[] spans = text.getSpans(0, 3, CustomTextLinkSpan.class); assertEquals(spans.length, 1); assertTrue(links.getLinks().contains(spans[0].getTextLink())); } }