blob: d2d03e56552281a09ea0f236db22a00b3584fb9b [file] [log] [blame]
Tony Mak0be540b2018-11-09 16:58:35 +00001/*
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
17package android.view.textclassifier;
18
19import static org.hamcrest.CoreMatchers.not;
20import static org.junit.Assert.assertEquals;
Tony Mak0be540b2018-11-09 16:58:35 +000021import static org.junit.Assert.assertThat;
22import static org.junit.Assert.assertTrue;
23
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +000024import android.app.RemoteAction;
Tony Mak0be540b2018-11-09 16:58:35 +000025import android.content.Context;
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +000026import android.content.Intent;
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +000027import android.os.Bundle;
Tony Mak0be540b2018-11-09 16:58:35 +000028import android.os.LocaleList;
Abodunrinwa Tokiadc19402018-11-22 17:10:25 +000029import android.text.Spannable;
30import android.text.SpannableString;
Tony Mak0be540b2018-11-09 16:58:35 +000031
Tadashi G. Takaokab4470f22019-01-15 18:29:15 +090032import androidx.test.InstrumentationRegistry;
33import androidx.test.filters.SmallTest;
34
Tony Mak0be540b2018-11-09 16:58:35 +000035import org.hamcrest.BaseMatcher;
36import org.hamcrest.Description;
37import org.hamcrest.Matcher;
38import org.junit.Before;
39import org.junit.Test;
40import org.junit.runner.RunWith;
41import org.junit.runners.Parameterized;
42
43import java.util.Arrays;
44import java.util.Collections;
45import java.util.List;
46
47/**
48 * Testing {@link TextClassifierTest} APIs on local and system textclassifier.
49 * <p>
50 * Tests are skipped if such a textclassifier does not exist.
51 */
52@SmallTest
53@RunWith(Parameterized.class)
54public class TextClassifierTest {
55 private static final String LOCAL = "local";
56 private static final String SYSTEM = "system";
57
58 @Parameterized.Parameters(name = "{0}")
59 public static Iterable<Object> textClassifierTypes() {
Abodunrinwa Tokiadc19402018-11-22 17:10:25 +000060 return Arrays.asList(LOCAL);
61
62 // TODO: The following will fail on any device that specifies a no-op TextClassifierService.
63 // Enable when we can set a specified TextClassifierService for testing.
64 // return Arrays.asList(LOCAL, SYSTEM);
Tony Mak0be540b2018-11-09 16:58:35 +000065 }
66
67 @Parameterized.Parameter
68 public String mTextClassifierType;
69
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +000070 private static final TextClassificationConstants TC_CONSTANTS =
71 TextClassificationConstants.loadFromString("");
Tony Mak0be540b2018-11-09 16:58:35 +000072 private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
73 private static final String NO_TYPE = null;
74
75 private Context mContext;
76 private TextClassificationManager mTcm;
77 private TextClassifier mClassifier;
78
79 @Before
80 public void setup() {
81 mContext = InstrumentationRegistry.getTargetContext();
82 mTcm = mContext.getSystemService(TextClassificationManager.class);
83 mClassifier = mTcm.getTextClassifier(
84 mTextClassifierType.equals(LOCAL) ? TextClassifier.LOCAL : TextClassifier.SYSTEM);
85 }
86
87 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +000088 public void testSuggestSelection() {
Tony Mak0be540b2018-11-09 16:58:35 +000089 if (isTextClassifierDisabled()) return;
90
91 String text = "Contact me at droid@android.com";
92 String selected = "droid";
93 String suggested = "droid@android.com";
94 int startIndex = text.indexOf(selected);
95 int endIndex = startIndex + selected.length();
96 int smartStartIndex = text.indexOf(suggested);
97 int smartEndIndex = smartStartIndex + suggested.length();
98 TextSelection.Request request = new TextSelection.Request.Builder(
99 text, startIndex, endIndex)
100 .setDefaultLocales(LOCALES)
101 .build();
102
103 TextSelection selection = mClassifier.suggestSelection(request);
104 assertThat(selection,
105 isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
106 }
107
108 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000109 public void testSuggestSelection_url() {
Tony Mak0be540b2018-11-09 16:58:35 +0000110 if (isTextClassifierDisabled()) return;
111
112 String text = "Visit http://www.android.com for more information";
113 String selected = "http";
114 String suggested = "http://www.android.com";
115 int startIndex = text.indexOf(selected);
116 int endIndex = startIndex + selected.length();
117 int smartStartIndex = text.indexOf(suggested);
118 int smartEndIndex = smartStartIndex + suggested.length();
119 TextSelection.Request request = new TextSelection.Request.Builder(
120 text, startIndex, endIndex)
121 .setDefaultLocales(LOCALES)
122 .build();
123
124 TextSelection selection = mClassifier.suggestSelection(request);
125 assertThat(selection,
126 isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
127 }
128
129 @Test
130 public void testSmartSelection_withEmoji() {
131 if (isTextClassifierDisabled()) return;
132
133 String text = "\uD83D\uDE02 Hello.";
134 String selected = "Hello";
135 int startIndex = text.indexOf(selected);
136 int endIndex = startIndex + selected.length();
137 TextSelection.Request request = new TextSelection.Request.Builder(
138 text, startIndex, endIndex)
139 .setDefaultLocales(LOCALES)
140 .build();
141
142 TextSelection selection = mClassifier.suggestSelection(request);
143 assertThat(selection,
144 isTextSelection(startIndex, endIndex, NO_TYPE));
145 }
146
147 @Test
148 public void testClassifyText() {
149 if (isTextClassifierDisabled()) return;
150
151 String text = "Contact me at droid@android.com";
152 String classifiedText = "droid@android.com";
153 int startIndex = text.indexOf(classifiedText);
154 int endIndex = startIndex + classifiedText.length();
155 TextClassification.Request request = new TextClassification.Request.Builder(
156 text, startIndex, endIndex)
157 .setDefaultLocales(LOCALES)
158 .build();
159
160 TextClassification classification = mClassifier.classifyText(request);
161 assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
162 }
163
164 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000165 public void testClassifyText_url() {
Tony Mak0be540b2018-11-09 16:58:35 +0000166 if (isTextClassifierDisabled()) return;
167
168 String text = "Visit www.android.com for more information";
169 String classifiedText = "www.android.com";
170 int startIndex = text.indexOf(classifiedText);
171 int endIndex = startIndex + classifiedText.length();
172 TextClassification.Request request = new TextClassification.Request.Builder(
173 text, startIndex, endIndex)
174 .setDefaultLocales(LOCALES)
175 .build();
176
177 TextClassification classification = mClassifier.classifyText(request);
178 assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
Abodunrinwa Tokic33fc772019-02-06 01:17:10 +0000179 assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
Tony Mak0be540b2018-11-09 16:58:35 +0000180 }
181
182 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000183 public void testClassifyText_address() {
Tony Mak0be540b2018-11-09 16:58:35 +0000184 if (isTextClassifierDisabled()) return;
185
186 String text = "Brandschenkestrasse 110, Zürich, Switzerland";
187 TextClassification.Request request = new TextClassification.Request.Builder(
188 text, 0, text.length())
189 .setDefaultLocales(LOCALES)
190 .build();
191
192 TextClassification classification = mClassifier.classifyText(request);
193 assertThat(classification, isTextClassification(text, TextClassifier.TYPE_ADDRESS));
194 }
195
196 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000197 public void testClassifyText_url_inCaps() {
Tony Mak0be540b2018-11-09 16:58:35 +0000198 if (isTextClassifierDisabled()) return;
199
200 String text = "Visit HTTP://ANDROID.COM for more information";
201 String classifiedText = "HTTP://ANDROID.COM";
202 int startIndex = text.indexOf(classifiedText);
203 int endIndex = startIndex + classifiedText.length();
204 TextClassification.Request request = new TextClassification.Request.Builder(
205 text, startIndex, endIndex)
206 .setDefaultLocales(LOCALES)
207 .build();
208
209 TextClassification classification = mClassifier.classifyText(request);
210 assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
Abodunrinwa Tokic33fc772019-02-06 01:17:10 +0000211 assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
Tony Mak0be540b2018-11-09 16:58:35 +0000212 }
213
214 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000215 public void testClassifyText_date() {
Tony Mak0be540b2018-11-09 16:58:35 +0000216 if (isTextClassifierDisabled()) return;
217
218 String text = "Let's meet on January 9, 2018.";
219 String classifiedText = "January 9, 2018";
220 int startIndex = text.indexOf(classifiedText);
221 int endIndex = startIndex + classifiedText.length();
222 TextClassification.Request request = new TextClassification.Request.Builder(
223 text, startIndex, endIndex)
224 .setDefaultLocales(LOCALES)
225 .build();
226
227 TextClassification classification = mClassifier.classifyText(request);
228 assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_DATE));
229 }
230
231 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000232 public void testClassifyText_datetime() {
Tony Mak0be540b2018-11-09 16:58:35 +0000233 if (isTextClassifierDisabled()) return;
234
235 String text = "Let's meet 2018/01/01 10:30:20.";
236 String classifiedText = "2018/01/01 10:30:20";
237 int startIndex = text.indexOf(classifiedText);
238 int endIndex = startIndex + classifiedText.length();
239 TextClassification.Request request = new TextClassification.Request.Builder(
240 text, startIndex, endIndex)
241 .setDefaultLocales(LOCALES)
242 .build();
243
244 TextClassification classification = mClassifier.classifyText(request);
245 assertThat(classification,
246 isTextClassification(classifiedText, TextClassifier.TYPE_DATE_TIME));
247 }
248
249 @Test
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000250 public void testClassifyText_foreignText() {
251 LocaleList originalLocales = LocaleList.getDefault();
252 LocaleList.setDefault(LocaleList.forLanguageTags("en"));
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +0000253 String japaneseText = "これは日本語のテキストです";
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000254
255 Context context = new FakeContextBuilder()
256 .setIntentComponent(Intent.ACTION_TRANSLATE, FakeContextBuilder.DEFAULT_COMPONENT)
257 .build();
258 TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS);
259 TextClassification.Request request = new TextClassification.Request.Builder(
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +0000260 japaneseText, 0, japaneseText.length())
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000261 .setDefaultLocales(LOCALES)
262 .build();
263
264 TextClassification classification = classifier.classifyText(request);
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +0000265 RemoteAction translateAction = classification.getActions().get(0);
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000266 assertEquals(1, classification.getActions().size());
267 assertEquals(
268 context.getString(com.android.internal.R.string.translate),
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +0000269 translateAction.getTitle());
270
271 assertEquals(translateAction, ExtrasUtils.findTranslateAction(classification));
272 Intent intent = ExtrasUtils.getActionsIntents(classification).get(0);
Abodunrinwa Toki385b10c2019-01-23 18:24:08 +0000273 assertEquals(Intent.ACTION_TRANSLATE, intent.getAction());
Abodunrinwa Toki520b2f82019-01-27 07:48:02 +0000274 Bundle foreignLanguageInfo = ExtrasUtils.getForeignLanguageExtra(classification);
275 assertEquals("ja", ExtrasUtils.getEntityType(foreignLanguageInfo));
276 assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) >= 0);
277 assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) <= 1);
Abodunrinwa Toki229f40a2018-11-27 20:08:00 +0000278
279 LocaleList.setDefault(originalLocales);
280 }
281
282 @Test
Tony Mak0be540b2018-11-09 16:58:35 +0000283 public void testGenerateLinks_phone() {
284 if (isTextClassifierDisabled()) return;
285 String text = "The number is +12122537077. See you tonight!";
286 TextLinks.Request request = new TextLinks.Request.Builder(text).build();
287 assertThat(mClassifier.generateLinks(request),
288 isTextLinksContaining(text, "+12122537077", TextClassifier.TYPE_PHONE));
289 }
290
291 @Test
292 public void testGenerateLinks_exclude() {
293 if (isTextClassifierDisabled()) return;
294 String text = "You want apple@banana.com. See you tonight!";
295 List<String> hints = Collections.EMPTY_LIST;
296 List<String> included = Collections.EMPTY_LIST;
297 List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
298 TextLinks.Request request = new TextLinks.Request.Builder(text)
299 .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
300 .setDefaultLocales(LOCALES)
301 .build();
302 assertThat(mClassifier.generateLinks(request),
303 not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
304 }
305
306 @Test
307 public void testGenerateLinks_explicit_address() {
308 if (isTextClassifierDisabled()) return;
309 String text = "The address is 1600 Amphitheater Parkway, Mountain View, CA. See you!";
310 List<String> explicit = Arrays.asList(TextClassifier.TYPE_ADDRESS);
311 TextLinks.Request request = new TextLinks.Request.Builder(text)
312 .setEntityConfig(TextClassifier.EntityConfig.createWithExplicitEntityList(explicit))
313 .setDefaultLocales(LOCALES)
314 .build();
315 assertThat(mClassifier.generateLinks(request),
316 isTextLinksContaining(text, "1600 Amphitheater Parkway, Mountain View, CA",
317 TextClassifier.TYPE_ADDRESS));
318 }
319
320 @Test
321 public void testGenerateLinks_exclude_override() {
322 if (isTextClassifierDisabled()) return;
323 String text = "You want apple@banana.com. See you tonight!";
324 List<String> hints = Collections.EMPTY_LIST;
325 List<String> included = Arrays.asList(TextClassifier.TYPE_EMAIL);
326 List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
327 TextLinks.Request request = new TextLinks.Request.Builder(text)
328 .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
329 .setDefaultLocales(LOCALES)
330 .build();
331 assertThat(mClassifier.generateLinks(request),
332 not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
333 }
334
335 @Test
336 public void testGenerateLinks_maxLength() {
337 if (isTextClassifierDisabled()) return;
338 char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
339 Arrays.fill(manySpaces, ' ');
340 TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
341 TextLinks links = mClassifier.generateLinks(request);
342 assertTrue(links.getLinks().isEmpty());
343 }
344
Abodunrinwa Tokiadc19402018-11-22 17:10:25 +0000345 @Test
346 public void testApplyLinks_unsupportedCharacter() {
347 if (isTextClassifierDisabled()) return;
348 Spannable url = new SpannableString("\u202Emoc.diordna.com");
349 TextLinks.Request request = new TextLinks.Request.Builder(url).build();
350 assertEquals(
351 TextLinks.STATUS_UNSUPPORTED_CHARACTER,
352 mClassifier.generateLinks(request).apply(url, 0, null));
353 }
354
355
Tony Mak0be540b2018-11-09 16:58:35 +0000356 @Test(expected = IllegalArgumentException.class)
357 public void testGenerateLinks_tooLong() {
358 if (isTextClassifierDisabled()) {
359 throw new IllegalArgumentException("pass if disabled");
360 }
361 char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
362 Arrays.fill(manySpaces, ' ');
363 TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
364 mClassifier.generateLinks(request);
365 }
366
367 @Test
368 public void testDetectLanguage() {
369 if (isTextClassifierDisabled()) return;
370 String text = "This is English text";
371 TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
372 TextLanguage textLanguage = mClassifier.detectLanguage(request);
373 assertThat(textLanguage, isTextLanguage("en"));
374 }
375
376 @Test
377 public void testDetectLanguage_japanese() {
378 if (isTextClassifierDisabled()) return;
379 String text = "これは日本語のテキストです";
380 TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
381 TextLanguage textLanguage = mClassifier.detectLanguage(request);
382 assertThat(textLanguage, isTextLanguage("ja"));
383 }
384
385 @Test
386 public void testSuggestConversationActions_textReplyOnly_maxThree() {
387 if (isTextClassifierDisabled()) return;
388 ConversationActions.Message message =
Tony Mak82fa8d92018-12-07 17:37:43 +0000389 new ConversationActions.Message.Builder(
Tony Mak91daa152019-01-24 16:00:28 +0000390 ConversationActions.Message.PERSON_USER_OTHERS)
Tony Makc4359bf2018-12-11 19:38:53 +0800391 .setText("Where are you?")
Tony Mak82fa8d92018-12-07 17:37:43 +0000392 .build();
Tony Makae85aae2019-01-09 15:59:56 +0000393 TextClassifier.EntityConfig typeConfig =
394 new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
Tony Mak0be540b2018-11-09 16:58:35 +0000395 .setIncludedTypes(
Tony Makae85aae2019-01-09 15:59:56 +0000396 Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
Tony Mak0be540b2018-11-09 16:58:35 +0000397 .build();
398 ConversationActions.Request request =
399 new ConversationActions.Request.Builder(Collections.singletonList(message))
Tony Makc4359bf2018-12-11 19:38:53 +0800400 .setMaxSuggestions(1)
Tony Mak0be540b2018-11-09 16:58:35 +0000401 .setTypeConfig(typeConfig)
402 .build();
403
404 ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
405 assertTrue(conversationActions.getConversationActions().size() > 0);
Tony Makc4359bf2018-12-11 19:38:53 +0800406 assertTrue(conversationActions.getConversationActions().size() == 1);
Tony Makae85aae2019-01-09 15:59:56 +0000407 for (ConversationAction conversationAction :
Tony Mak0be540b2018-11-09 16:58:35 +0000408 conversationActions.getConversationActions()) {
Tony Makc4359bf2018-12-11 19:38:53 +0800409 assertThat(conversationAction,
Tony Makae85aae2019-01-09 15:59:56 +0000410 isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
Tony Makc4359bf2018-12-11 19:38:53 +0800411 }
Tony Mak128a61d2019-01-28 18:57:26 +0000412 }
Tony Makc4359bf2018-12-11 19:38:53 +0800413
414 @Test
415 public void testSuggestConversationActions_textReplyOnly_noMax() {
416 if (isTextClassifierDisabled()) return;
417 ConversationActions.Message message =
418 new ConversationActions.Message.Builder(
Tony Mak91daa152019-01-24 16:00:28 +0000419 ConversationActions.Message.PERSON_USER_OTHERS)
Tony Makc4359bf2018-12-11 19:38:53 +0800420 .setText("Where are you?")
421 .build();
Tony Makae85aae2019-01-09 15:59:56 +0000422 TextClassifier.EntityConfig typeConfig =
423 new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
Tony Makc4359bf2018-12-11 19:38:53 +0800424 .setIncludedTypes(
Tony Makae85aae2019-01-09 15:59:56 +0000425 Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
Tony Makc4359bf2018-12-11 19:38:53 +0800426 .build();
427 ConversationActions.Request request =
428 new ConversationActions.Request.Builder(Collections.singletonList(message))
429 .setTypeConfig(typeConfig)
430 .build();
431
432 ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
433 assertTrue(conversationActions.getConversationActions().size() > 1);
Tony Makae85aae2019-01-09 15:59:56 +0000434 for (ConversationAction conversationAction :
Tony Makc4359bf2018-12-11 19:38:53 +0800435 conversationActions.getConversationActions()) {
436 assertThat(conversationAction,
Tony Makae85aae2019-01-09 15:59:56 +0000437 isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
Tony Mak0be540b2018-11-09 16:58:35 +0000438 }
439 }
440
441
442 private boolean isTextClassifierDisabled() {
443 return mClassifier == null || mClassifier == TextClassifier.NO_OP;
444 }
445
446 private static Matcher<TextSelection> isTextSelection(
447 final int startIndex, final int endIndex, final String type) {
448 return new BaseMatcher<TextSelection>() {
449 @Override
450 public boolean matches(Object o) {
451 if (o instanceof TextSelection) {
452 TextSelection selection = (TextSelection) o;
453 return startIndex == selection.getSelectionStartIndex()
454 && endIndex == selection.getSelectionEndIndex()
455 && typeMatches(selection, type);
456 }
457 return false;
458 }
459
460 private boolean typeMatches(TextSelection selection, String type) {
461 return type == null
462 || (selection.getEntityCount() > 0
463 && type.trim().equalsIgnoreCase(selection.getEntity(0)));
464 }
465
466 @Override
467 public void describeTo(Description description) {
468 description.appendValue(
469 String.format("%d, %d, %s", startIndex, endIndex, type));
470 }
471 };
472 }
473
474 private static Matcher<TextLinks> isTextLinksContaining(
475 final String text, final String substring, final String type) {
476 return new BaseMatcher<TextLinks>() {
477
478 @Override
479 public void describeTo(Description description) {
480 description.appendText("text=").appendValue(text)
481 .appendText(", substring=").appendValue(substring)
482 .appendText(", type=").appendValue(type);
483 }
484
485 @Override
486 public boolean matches(Object o) {
487 if (o instanceof TextLinks) {
488 for (TextLinks.TextLink link : ((TextLinks) o).getLinks()) {
489 if (text.subSequence(link.getStart(), link.getEnd()).equals(substring)) {
490 return type.equals(link.getEntity(0));
491 }
492 }
493 }
494 return false;
495 }
496 };
497 }
498
499 private static Matcher<TextClassification> isTextClassification(
500 final String text, final String type) {
501 return new BaseMatcher<TextClassification>() {
502 @Override
503 public boolean matches(Object o) {
504 if (o instanceof TextClassification) {
505 TextClassification result = (TextClassification) o;
506 return text.equals(result.getText())
507 && result.getEntityCount() > 0
508 && type.equals(result.getEntity(0));
509 }
510 return false;
511 }
512
513 @Override
514 public void describeTo(Description description) {
515 description.appendText("text=").appendValue(text)
516 .appendText(", type=").appendValue(type);
517 }
518 };
519 }
520
Abodunrinwa Tokic33fc772019-02-06 01:17:10 +0000521 private static Matcher<TextClassification> containsIntentWithAction(final String action) {
522 return new BaseMatcher<TextClassification>() {
523 @Override
524 public boolean matches(Object o) {
525 if (o instanceof TextClassification) {
526 TextClassification result = (TextClassification) o;
527 return ExtrasUtils.findAction(result, action) != null;
528 }
529 return false;
530 }
531
532 @Override
533 public void describeTo(Description description) {
534 description.appendText("intent action=").appendValue(action);
535 }
536 };
537 }
538
Tony Mak0be540b2018-11-09 16:58:35 +0000539 private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
540 return new BaseMatcher<TextLanguage>() {
541 @Override
542 public boolean matches(Object o) {
543 if (o instanceof TextLanguage) {
544 TextLanguage result = (TextLanguage) o;
545 return result.getLocaleHypothesisCount() > 0
546 && languageTag.equals(result.getLocale(0).toLanguageTag());
547 }
548 return false;
549 }
550
551 @Override
552 public void describeTo(Description description) {
553 description.appendText("locale=").appendValue(languageTag);
554 }
555 };
556 }
Tony Makc4359bf2018-12-11 19:38:53 +0800557
Tony Makae85aae2019-01-09 15:59:56 +0000558 private static Matcher<ConversationAction> isConversationAction(String actionType) {
559 return new BaseMatcher<ConversationAction>() {
Tony Makc4359bf2018-12-11 19:38:53 +0800560 @Override
561 public boolean matches(Object o) {
Tony Makae85aae2019-01-09 15:59:56 +0000562 if (!(o instanceof ConversationAction)) {
Tony Makc4359bf2018-12-11 19:38:53 +0800563 return false;
564 }
Tony Makae85aae2019-01-09 15:59:56 +0000565 ConversationAction conversationAction =
566 (ConversationAction) o;
Tony Makc4359bf2018-12-11 19:38:53 +0800567 if (!actionType.equals(conversationAction.getType())) {
568 return false;
569 }
Tony Makae85aae2019-01-09 15:59:56 +0000570 if (ConversationAction.TYPE_TEXT_REPLY.equals(actionType)) {
Tony Makc4359bf2018-12-11 19:38:53 +0800571 if (conversationAction.getTextReply() == null) {
572 return false;
573 }
574 }
575 if (conversationAction.getConfidenceScore() < 0
576 || conversationAction.getConfidenceScore() > 1) {
577 return false;
578 }
579 return true;
580 }
581
582 @Override
583 public void describeTo(Description description) {
584 description.appendText("actionType=").appendValue(actionType);
585 }
586 };
587 }
Tony Mak0be540b2018-11-09 16:58:35 +0000588}