1 /* 2 * Copyright (C) 2018 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 17 package androidx.textclassifier; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 22 import android.os.Parcel; 23 import android.support.test.filters.SmallTest; 24 import android.support.test.runner.AndroidJUnit4; 25 import android.text.Spannable; 26 import android.text.SpannableString; 27 import android.text.style.ClickableSpan; 28 import android.view.View; 29 30 import androidx.annotation.Nullable; 31 import androidx.collection.ArrayMap; 32 import androidx.core.os.LocaleListCompat; 33 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.List; 41 import java.util.Map; 42 43 /** Instrumentation unit tests for {@link TextLinks}. */ 44 @SmallTest 45 @RunWith(AndroidJUnit4.class) 46 public final class TextLinksTest { 47 48 private static class NoOpSpan extends ClickableSpan { 49 @Override 50 public void onClick(View v) { 51 // Do nothing. 52 } 53 } 54 55 private static class CustomTextLinkSpan extends TextLinks.TextLinkSpan { 56 CustomTextLinkSpan(@Nullable TextLinks.TextLink textLink) { 57 super(textLink); 58 } 59 } 60 61 private static class CustomSpanFactory implements TextLinks.SpanFactory { 62 @Override 63 public TextLinks.TextLinkSpan createSpan(TextLinks.TextLink textLink) { 64 return new CustomTextLinkSpan(textLink); 65 } 66 } 67 68 private TextClassifier mClassifier; 69 private Map<String, Float> mDummyEntityScores; 70 71 @Before 72 public void setup() { 73 mClassifier = new TextClassifier(); 74 mDummyEntityScores = new ArrayMap<>(); 75 mDummyEntityScores.put(TextClassifier.TYPE_ADDRESS, 0.2f); 76 mDummyEntityScores.put(TextClassifier.TYPE_PHONE, 0.7f); 77 mDummyEntityScores.put(TextClassifier.TYPE_OTHER, 0.3f); 78 } 79 80 private Map<String, Float> getEntityScores(float address, float phone, float other) { 81 final Map<String, Float> result = new ArrayMap<>(); 82 if (address > 0.f) { 83 result.put(TextClassifier.TYPE_ADDRESS, address); 84 } 85 if (phone > 0.f) { 86 result.put(TextClassifier.TYPE_PHONE, phone); 87 } 88 if (other > 0.f) { 89 result.put(TextClassifier.TYPE_OTHER, other); 90 } 91 return result; 92 } 93 94 @Test 95 public void testParcel() { 96 final String fullText = "this is just a test"; 97 final TextLinks reference = new TextLinks.Builder(fullText) 98 .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f)) 99 .addLink(5, 12, getEntityScores(.8f, .1f, .5f)) 100 .build(); 101 102 // Parcel and unparcel. 103 final Parcel parcel = Parcel.obtain(); 104 reference.writeToParcel(parcel, reference.describeContents()); 105 parcel.setDataPosition(0); 106 final TextLinks result = TextLinks.CREATOR.createFromParcel(parcel); 107 final List<TextLinks.TextLink> resultList = new ArrayList<>(result.getLinks()); 108 109 assertEquals(2, resultList.size()); 110 assertEquals(0, resultList.get(0).getStart()); 111 assertEquals(4, resultList.get(0).getEnd()); 112 assertEquals(1, resultList.get(0).getEntityCount()); 113 assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0)); 114 assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER), 115 1e-7f); 116 assertEquals(5, resultList.get(1).getStart()); 117 assertEquals(12, resultList.get(1).getEnd()); 118 assertEquals(3, resultList.get(1).getEntityCount()); 119 assertEquals(TextClassifier.TYPE_ADDRESS, resultList.get(1).getEntity(0)); 120 assertEquals(TextClassifier.TYPE_OTHER, resultList.get(1).getEntity(1)); 121 assertEquals(TextClassifier.TYPE_PHONE, resultList.get(1).getEntity(2)); 122 assertEquals(.8f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f); 123 assertEquals(.5f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f); 124 assertEquals(.1f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f); 125 } 126 127 @Test 128 public void testParcelOptions() { 129 TextClassifier.EntityConfig entityConfig = new TextClassifier.EntityConfig( 130 TextClassifier.ENTITY_PRESET_NONE); 131 entityConfig.includeEntities("a", "b", "c"); 132 entityConfig.excludeEntities("b"); 133 final String callingPackageName = "packageName"; 134 TextLinks.Options reference = new TextLinks.Options() 135 .setDefaultLocales(LocaleListCompat.forLanguageTags("en-US,de-DE")) 136 .setEntityConfig(entityConfig) 137 .setApplyStrategy(TextLinks.APPLY_STRATEGY_REPLACE) 138 .setSpanFactory(new CustomSpanFactory()) 139 .setCallingPackageName(callingPackageName); 140 141 final Parcel parcel = Parcel.obtain(); 142 reference.writeToParcel(parcel, reference.describeContents()); 143 parcel.setDataPosition(0); 144 TextLinks.Options result = TextLinks.Options.CREATOR.createFromParcel(parcel); 145 146 assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags()); 147 assertEquals(Arrays.asList("a", "c"), result.getEntityConfig().getEntities(mClassifier)); 148 assertEquals(TextLinks.APPLY_STRATEGY_REPLACE, result.getApplyStrategy()); 149 assertEquals(null, result.getSpanFactory()); 150 assertEquals(callingPackageName, result.getCallingPackageName()); 151 } 152 153 @Test 154 public void testApplyDifferentText() { 155 SpannableString text = new SpannableString("foo"); 156 TextLinks links = new TextLinks.Builder("bar").build(); 157 assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null), 158 TextLinks.STATUS_DIFFERENT_TEXT); 159 } 160 161 @Test 162 public void testApplyNoLinks() { 163 SpannableString text = new SpannableString("foo"); 164 TextLinks links = new TextLinks.Builder(text.toString()).build(); 165 assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null), 166 TextLinks.STATUS_NO_LINKS_FOUND); 167 } 168 169 @Test 170 public void testApplyNoApplied() { 171 SpannableString text = new SpannableString("foo"); 172 text.setSpan(new NoOpSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 173 TextLinks links = new TextLinks.Builder(text.toString()).addLink( 174 0, 3, mDummyEntityScores).build(); 175 assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, null), 176 TextLinks.STATUS_NO_LINKS_APPLIED); 177 } 178 179 @Test 180 public void testApplyAppliedDefaultSpanFactory() { 181 SpannableString text = new SpannableString("foo"); 182 TextLinks links = new TextLinks.Builder(text.toString()).addLink( 183 0, 3, mDummyEntityScores).build(); 184 assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, null), 185 TextLinks.STATUS_LINKS_APPLIED); 186 TextLinks.TextLinkSpan[] spans = text.getSpans(0, 3, TextLinks.TextLinkSpan.class); 187 assertEquals(spans.length, 1); 188 assertTrue(links.getLinks().contains(spans[0].getTextLink())); 189 } 190 191 @Test 192 public void testApplyAppliedDefaultSpanFactoryReplace() { 193 SpannableString text = new SpannableString("foo"); 194 text.setSpan(new NoOpSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 195 TextLinks links = new TextLinks.Builder(text.toString()).addLink( 196 0, 3, mDummyEntityScores).build(); 197 assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null), 198 TextLinks.STATUS_LINKS_APPLIED); 199 TextLinks.TextLinkSpan[] spans = text.getSpans(0, 3, TextLinks.TextLinkSpan.class); 200 assertEquals(spans.length, 1); 201 assertTrue(links.getLinks().contains(spans[0].getTextLink())); 202 } 203 204 @Test 205 public void testApplyAppliedCustomSpanFactory() { 206 SpannableString text = new SpannableString("foo"); 207 TextLinks links = new TextLinks.Builder(text.toString()).addLink( 208 0, 3, mDummyEntityScores).build(); 209 assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, new CustomSpanFactory()), 210 TextLinks.STATUS_LINKS_APPLIED); 211 CustomTextLinkSpan[] spans = text.getSpans(0, 3, CustomTextLinkSpan.class); 212 assertEquals(spans.length, 1); 213 assertTrue(links.getLinks().contains(spans[0].getTextLink())); 214 } 215 } 216