EmojiCompatTest.java revision 9546df94e6393de504f7ef8dc1b12a1f550c47a8
1/* 2 * Copyright (C) 2017 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 */ 16package android.support.text.emoji; 17 18import static android.support.text.emoji.TestConfigBuilder.TestConfig; 19import static android.support.text.emoji.TestConfigBuilder.WaitingDataLoader; 20import static android.support.text.emoji.TestConfigBuilder.config; 21import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_EMOJI_STYLE; 22import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_TEXT_STYLE; 23import static android.support.text.emoji.util.Emoji.CHAR_DIGIT; 24import static android.support.text.emoji.util.Emoji.CHAR_FITZPATRICK; 25import static android.support.text.emoji.util.Emoji.CHAR_VS_EMOJI; 26import static android.support.text.emoji.util.Emoji.CHAR_VS_TEXT; 27import static android.support.text.emoji.util.Emoji.DEFAULT_TEXT_STYLE; 28import static android.support.text.emoji.util.Emoji.EMOJI_ASTERISK_KEYCAP; 29import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES; 30import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES_KEYCAP; 31import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_KEYCAP; 32import static android.support.text.emoji.util.Emoji.EMOJI_FLAG; 33import static android.support.text.emoji.util.Emoji.EMOJI_GENDER; 34import static android.support.text.emoji.util.Emoji.EMOJI_GENDER_WITHOUT_VS; 35import static android.support.text.emoji.util.Emoji.EMOJI_REGIONAL_SYMBOL; 36import static android.support.text.emoji.util.Emoji.EMOJI_SINGLE_CODEPOINT; 37import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER; 38import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_TYPE_ONE; 39import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_WITH_VS; 40import static android.support.text.emoji.util.Emoji.EMOJI_UNKNOWN_FLAG; 41import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ; 42import static android.support.text.emoji.util.EmojiMatcher.hasEmoji; 43import static android.support.text.emoji.util.EmojiMatcher.hasEmojiAt; 44import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount; 45import static android.support.text.emoji.util.KeyboardUtil.del; 46 47import static junit.framework.TestCase.assertFalse; 48 49import static org.hamcrest.Matchers.instanceOf; 50import static org.hamcrest.Matchers.not; 51import static org.junit.Assert.assertEquals; 52import static org.junit.Assert.assertNotNull; 53import static org.junit.Assert.assertNull; 54import static org.junit.Assert.assertSame; 55import static org.junit.Assert.assertThat; 56import static org.junit.Assert.assertTrue; 57import static org.mockito.Mockito.mock; 58import static org.mockito.Mockito.reset; 59import static org.mockito.Mockito.spy; 60import static org.mockito.Mockito.verifyNoMoreInteractions; 61 62import android.annotation.SuppressLint; 63import android.os.Bundle; 64import android.support.test.InstrumentationRegistry; 65import android.support.test.filters.SdkSuppress; 66import android.support.test.filters.SmallTest; 67import android.support.test.runner.AndroidJUnit4; 68import android.support.text.emoji.EmojiCompat.Config; 69import android.support.text.emoji.util.Emoji.EmojiMapping; 70import android.support.text.emoji.util.TestString; 71import android.text.Editable; 72import android.text.Selection; 73import android.text.Spannable; 74import android.text.SpannableString; 75import android.text.SpannableStringBuilder; 76import android.text.SpannedString; 77import android.view.KeyEvent; 78import android.view.inputmethod.EditorInfo; 79import android.view.inputmethod.InputConnection; 80 81import org.junit.Before; 82import org.junit.Test; 83import org.junit.runner.RunWith; 84 85import java.util.Collections; 86import java.util.HashSet; 87import java.util.Set; 88 89@SmallTest 90@RunWith(AndroidJUnit4.class) 91public class EmojiCompatTest { 92 93 @Before 94 public void setup() { 95 EmojiCompat.reset(config()); 96 } 97 98 @Test(expected = IllegalStateException.class) 99 public void testGet_throwsException() { 100 EmojiCompat.reset((EmojiCompat) null); 101 EmojiCompat.get(); 102 } 103 104 @Test 105 public void testProcess_doesNothing_withNullCharSequence() { 106 assertNull(EmojiCompat.get().process(null)); 107 } 108 109 @Test 110 public void testProcess_returnsEmptySpanned_withEmptyString() { 111 final CharSequence charSequence = EmojiCompat.get().process(""); 112 assertNotNull(charSequence); 113 assertEquals(0, charSequence.length()); 114 assertThat(charSequence, not(hasEmoji())); 115 } 116 117 @SuppressLint("Range") 118 @Test(expected = IllegalArgumentException.class) 119 public void testProcess_withNegativeStartValue() { 120 EmojiCompat.get().process("a", -1, 1); 121 } 122 123 @SuppressLint("Range") 124 @Test(expected = IllegalArgumentException.class) 125 public void testProcess_withNegativeEndValue() { 126 EmojiCompat.get().process("a", 1, -1); 127 } 128 129 @Test(expected = IllegalArgumentException.class) 130 public void testProcess_withStartSmallerThanEndValue() { 131 EmojiCompat.get().process("aa", 1, 0); 132 } 133 134 @Test(expected = IllegalArgumentException.class) 135 public void testProcess_withStartGreaterThanLength() { 136 EmojiCompat.get().process("a", 2, 2); 137 } 138 139 @Test(expected = IllegalArgumentException.class) 140 public void testProcess_withEndGreaterThanLength() { 141 EmojiCompat.get().process("a", 0, 2); 142 } 143 144 @Test 145 public void testProcessWithStartEnd_withNoOpValues() { 146 final Spannable spannable = new SpannableString(new TestString('a') 147 .withPrefix().withSuffix().toString()); 148 // early return check 149 assertSame(spannable, EmojiCompat.get().process(spannable, 0, 0)); 150 assertSame(spannable, EmojiCompat.get().process(spannable, 1, 1)); 151 assertSame(spannable, EmojiCompat.get().process(spannable, spannable.length(), 152 spannable.length())); 153 } 154 155 @Test 156 public void testProcess_doesNotAddEmojiSpan() { 157 final String string = "abc"; 158 final CharSequence charSequence = EmojiCompat.get().process(string); 159 assertNotNull(charSequence); 160 assertEquals(string, charSequence.toString()); 161 assertThat(charSequence, not(hasEmoji())); 162 } 163 164 @Test 165 @SdkSuppress(maxSdkVersion = 18) 166 public void testProcess_returnsSameCharSequence_pre19() { 167 assertNull(EmojiCompat.get().process(null)); 168 169 CharSequence testString = "abc"; 170 assertSame(testString, EmojiCompat.get().process(testString)); 171 172 testString = new SpannableString("abc"); 173 assertSame(testString, EmojiCompat.get().process(testString)); 174 175 testString = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString(); 176 assertSame(testString, EmojiCompat.get().process(testString)); 177 } 178 179 @Test 180 @SdkSuppress(minSdkVersion = 19) 181 public void testProcess_addsSingleCodePointEmoji() { 182 assertCodePointMatch(EMOJI_SINGLE_CODEPOINT); 183 } 184 185 @Test 186 @SdkSuppress(minSdkVersion = 19) 187 public void testProcess_addsFlagEmoji() { 188 assertCodePointMatch(EMOJI_FLAG); 189 } 190 191 @Test 192 @SdkSuppress(minSdkVersion = 19) 193 public void testProcess_addsUnknownFlagEmoji() { 194 assertCodePointMatch(EMOJI_UNKNOWN_FLAG); 195 } 196 197 @Test 198 @SdkSuppress(minSdkVersion = 19) 199 public void testProcess_addsRegionalIndicatorSymbol() { 200 assertCodePointMatch(EMOJI_REGIONAL_SYMBOL); 201 } 202 203 @Test 204 @SdkSuppress(minSdkVersion = 19) 205 public void testProcess_addsKeyCapEmoji() { 206 assertCodePointMatch(EMOJI_DIGIT_KEYCAP); 207 } 208 209 @Test 210 @SdkSuppress(minSdkVersion = 19) 211 public void testProcess_doesNotAddEmojiForNumbers() { 212 assertCodePointDoesNotMatch(new int[] {CHAR_DIGIT}); 213 } 214 215 @Test 216 @SdkSuppress(minSdkVersion = 19) 217 public void testProcess_doesNotAddEmojiForNumbers_1() { 218 final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).append('1', 'f'); 219 CharSequence charSequence = EmojiCompat.get().process(string.toString()); 220 assertThat(charSequence, hasEmojiCount(1)); 221 } 222 223 @Test 224 @SdkSuppress(minSdkVersion = 19) 225 public void testProcess_addsVariantSelectorEmoji() { 226 assertCodePointMatch(EMOJI_DIGIT_ES); 227 } 228 229 @Test 230 @SdkSuppress(minSdkVersion = 19) 231 public void testProcess_doesNotAddVariantSelectorTextStyle() { 232 assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT, CHAR_VS_TEXT}); 233 } 234 235 @Test 236 @SdkSuppress(minSdkVersion = 19) 237 public void testProcess_addsVariantSelectorAndKeyCapEmoji() { 238 assertCodePointMatch(EMOJI_DIGIT_ES_KEYCAP); 239 } 240 241 @Test 242 public void testProcess_doesNotAddEmoji_forVariantBaseWithoutSelector() { 243 assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT}); 244 } 245 246 @Test 247 @SdkSuppress(minSdkVersion = 19) 248 public void testProcess_addsAsteriskKeyCapEmoji() { 249 assertCodePointMatch(EMOJI_ASTERISK_KEYCAP); 250 } 251 252 @Test 253 @SdkSuppress(minSdkVersion = 19) 254 public void testProcess_addsSkinModifierEmoji() { 255 assertCodePointMatch(EMOJI_SKIN_MODIFIER); 256 assertCodePointMatch(EMOJI_SKIN_MODIFIER_TYPE_ONE); 257 } 258 259 @Test 260 @SdkSuppress(minSdkVersion = 19) 261 public void testProcess_addsSkinModifierEmoji_withVariantSelector() { 262 assertCodePointMatch(EMOJI_SKIN_MODIFIER_WITH_VS); 263 } 264 265 @Test 266 @SdkSuppress(minSdkVersion = 19) 267 public void testProcess_addsSkinModifierEmoji_270c_withVariantSelector() { 268 // 0x270c is a Standardized Variant Base, Emoji Modifier Base and also Emoji 269 // therefore it is different than i.e. 0x1f3c3. The code actually failed for this test 270 // at first. 271 assertCodePointMatch(0xF0734, new int[]{0x270C, CHAR_VS_EMOJI, CHAR_FITZPATRICK}); 272 } 273 274 @Test 275 @SdkSuppress(minSdkVersion = 19) 276 public void testProcess_defaultStyleDoesNotAddSpan() { 277 assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_TEXT_STYLE}); 278 assertCodePointMatch(DEFAULT_TEXT_STYLE); 279 } 280 281 @Test 282 @SdkSuppress(minSdkVersion = 19) 283 public void testProcess_defaultEmojiStyle_withTextStyleVs() { 284 assertCodePointMatch(EMOJI_SINGLE_CODEPOINT.id(), 285 new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI}); 286 assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT}); 287 } 288 289 @Test 290 @SdkSuppress(minSdkVersion = 19) 291 public void testProcess_genderEmoji() { 292 assertCodePointMatch(EMOJI_GENDER); 293 assertCodePointMatch(EMOJI_GENDER_WITHOUT_VS); 294 } 295 296 @Test 297 @SdkSuppress(minSdkVersion = 19) 298 public void testProcess_standardizedVariantEmojiExceptions() { 299 final int[][] exceptions = new int[][]{ 300 {0x2600, 0xF034D}, 301 {0x2601, 0xF0167}, 302 {0x260E, 0xF034E}, 303 {0x261D, 0xF0227}, 304 {0x263A, 0xF02A6}, 305 {0x2660, 0xF0350}, 306 {0x2663, 0xF033F}, 307 {0x2665, 0xF033B}, 308 {0x2666, 0xF033E}, 309 {0x270C, 0xF0079}, 310 {0x2744, 0xF0342}, 311 {0x2764, 0xF0362} 312 }; 313 314 for (int i = 0; i < exceptions.length; i++) { 315 final int[] codepoints = new int[]{exceptions[i][0]}; 316 assertCodePointMatch(exceptions[i][1], codepoints); 317 } 318 } 319 320 @Test 321 @SdkSuppress(minSdkVersion = 19) 322 public void testProcess_addsZwjEmoji() { 323 assertCodePointMatch(EMOJI_WITH_ZWJ); 324 } 325 326 @Test 327 @SdkSuppress(minSdkVersion = 19) 328 public void testProcess_doesNotAddEmojiForNumbersAfterZwjEmo() { 329 TestString string = new TestString(EMOJI_WITH_ZWJ).append(0x20, 0x2B, 0x31) 330 .withSuffix().withPrefix(); 331 CharSequence charSequence = EmojiCompat.get().process(string.toString()); 332 assertThat(charSequence, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(), 333 string.emojiEndIndex() - 3)); 334 assertThat(charSequence, hasEmojiCount(1)); 335 336 string = new TestString(EMOJI_WITH_ZWJ).withSuffix().withPrefix(); 337 charSequence = EmojiCompat.get().process(string.toString()); 338 assertThat(charSequence, hasEmojiCount(1)); 339 } 340 341 @Test 342 @SdkSuppress(minSdkVersion = 19) 343 public void testProcess_withAppend() { 344 final Editable editable = new SpannableStringBuilder(new TestString('a').withPrefix() 345 .withSuffix().toString()); 346 final int start = 1; 347 final int end = start + EMOJI_SINGLE_CODEPOINT.charCount(); 348 editable.insert(start, new TestString(EMOJI_SINGLE_CODEPOINT).toString()); 349 EmojiCompat.get().process(editable, start, end); 350 assertThat(editable, hasEmojiCount(1)); 351 assertThat(editable, hasEmojiAt(EMOJI_SINGLE_CODEPOINT, start, end)); 352 } 353 354 @Test 355 public void testProcess_doesNotCreateSpannable_ifNoEmoji() { 356 CharSequence processed = EmojiCompat.get().process("abc"); 357 assertNotNull(processed); 358 assertThat(processed, instanceOf(String.class)); 359 360 processed = EmojiCompat.get().process(new SpannedString("abc")); 361 assertNotNull(processed); 362 assertThat(processed, instanceOf(SpannedString.class)); 363 } 364 365 @Test 366 @SdkSuppress(minSdkVersion = 19) 367 public void testProcess_reprocess() { 368 final String string = new TestString(EMOJI_SINGLE_CODEPOINT) 369 .append(EMOJI_SINGLE_CODEPOINT) 370 .append(EMOJI_SINGLE_CODEPOINT) 371 .withPrefix().withSuffix().toString(); 372 373 Spannable processed = (Spannable) EmojiCompat.get().process(string); 374 assertThat(processed, hasEmojiCount(3)); 375 376 final EmojiSpan[] spans = processed.getSpans(0, processed.length(), EmojiSpan.class); 377 final Set<EmojiSpan> spanSet = new HashSet<>(); 378 Collections.addAll(spanSet, spans); 379 380 processed = (Spannable) EmojiCompat.get().process(processed); 381 assertThat(processed, hasEmojiCount(3)); 382 // new spans should be new instances 383 final EmojiSpan[] newSpans = processed.getSpans(0, processed.length(), EmojiSpan.class); 384 for (int i = 0; i < newSpans.length; i++) { 385 assertFalse(spanSet.contains(newSpans[i])); 386 } 387 } 388 389 @SuppressLint("Range") 390 @Test(expected = IllegalArgumentException.class) 391 public void testProcess_throwsException_withMaxEmojiSetToNegative() { 392 final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString(); 393 394 final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 395 -1 /*maxEmojiCount*/); 396 397 assertThat(processed, not(hasEmoji())); 398 } 399 400 @Test 401 public void testProcess_withMaxEmojiSetToZero() { 402 final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString(); 403 404 final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 405 0 /*maxEmojiCount*/); 406 407 assertThat(processed, not(hasEmoji())); 408 } 409 410 @Test 411 @SdkSuppress(minSdkVersion = 19) 412 public void testProcess_withMaxEmojiSetToOne() { 413 final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString(); 414 415 final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 416 1 /*maxEmojiCount*/); 417 418 assertThat(processed, hasEmojiCount(1)); 419 assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT)); 420 } 421 422 @Test 423 @SdkSuppress(minSdkVersion = 19) 424 public void testProcess_withMaxEmojiSetToLessThenExistingSpanCount() { 425 final String original = new TestString(EMOJI_SINGLE_CODEPOINT) 426 .append(EMOJI_SINGLE_CODEPOINT) 427 .append(EMOJI_SINGLE_CODEPOINT) 428 .toString(); 429 430 // add 2 spans 431 final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 2); 432 433 assertThat(processed, hasEmojiCount(2)); 434 435 // use the Spannable with 2 spans, but use maxEmojiCount=1, start from the beginning of 436 // last (3rd) emoji 437 EmojiCompat.get().process(processed, original.length() - EMOJI_SINGLE_CODEPOINT.charCount(), 438 original.length(), 1 /*maxEmojiCount*/); 439 440 // expectation: there are still 2 emojis 441 assertThat(processed, hasEmojiCount(2)); 442 } 443 444 @Test 445 @SdkSuppress(minSdkVersion = 19) 446 public void testProcess_withMaxEmojiSet_withExistingEmojis() { 447 // test string with two emoji characters 448 final String original = new TestString(EMOJI_SINGLE_CODEPOINT) 449 .append(EMOJI_FLAG).toString(); 450 451 // process and add 1 EmojiSpan, maxEmojiCount=1 452 CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 453 1 /*maxEmojiCount*/); 454 455 // assert that there is a single emoji 456 assertThat(processed, hasEmojiCount(1)); 457 assertThat(processed, 458 hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount())); 459 460 // call process again with the charSequence that already has 1 span 461 processed = EmojiCompat.get().process(processed, EMOJI_SINGLE_CODEPOINT.charCount(), 462 processed.length(), 1 /*maxEmojiCount*/); 463 464 // assert that there is still a single emoji 465 assertThat(processed, hasEmojiCount(1)); 466 assertThat(processed, 467 hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount())); 468 469 // make the same call, this time with maxEmojiCount=2 470 processed = EmojiCompat.get().process(processed, EMOJI_SINGLE_CODEPOINT.charCount(), 471 processed.length(), 2 /*maxEmojiCount*/); 472 473 // assert that it contains 2 emojis 474 assertThat(processed, hasEmojiCount(2)); 475 assertThat(processed, 476 hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount())); 477 assertThat(processed, 478 hasEmojiAt(EMOJI_FLAG, EMOJI_SINGLE_CODEPOINT.charCount(), 479 original.length())); 480 } 481 482 @Test(expected = NullPointerException.class) 483 public void testHasEmojiGlyph_withNullCharSequence() { 484 EmojiCompat.get().hasEmojiGlyph(null); 485 } 486 487 @Test(expected = NullPointerException.class) 488 public void testHasEmojiGlyph_withMetadataVersion_withNullCharSequence() { 489 EmojiCompat.get().hasEmojiGlyph(null, Integer.MAX_VALUE); 490 } 491 492 @Test 493 @SdkSuppress(maxSdkVersion = 18) 494 public void testHasEmojiGlyph_pre19() { 495 String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString(); 496 assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence)); 497 } 498 499 @Test 500 @SdkSuppress(maxSdkVersion = 18) 501 public void testHasEmojiGlyph_withMetaVersion_pre19() { 502 String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString(); 503 assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE)); 504 } 505 506 @Test 507 @SdkSuppress(minSdkVersion = 19) 508 public void testHasEmojiGlyph_returnsTrueForExistingEmoji() { 509 final String sequence = new TestString(EMOJI_FLAG).toString(); 510 assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence)); 511 } 512 513 @Test 514 public void testHasGlyph_returnsFalseForNonExistentEmoji() { 515 final String sequence = new TestString(EMOJI_FLAG).append(0x1111).toString(); 516 assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence)); 517 } 518 519 @Test 520 @SdkSuppress(minSdkVersion = 19) 521 public void testHashEmojiGlyph_withDefaultEmojiStyles() { 522 String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString(); 523 assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence)); 524 525 sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI}).toString(); 526 assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence)); 527 528 sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT}).toString(); 529 assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence)); 530 } 531 532 @Test 533 @SdkSuppress(minSdkVersion = 19) 534 public void testHashEmojiGlyph_withMetadataVersion() { 535 final String sequence = new TestString(EMOJI_SINGLE_CODEPOINT).toString(); 536 assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, 0)); 537 assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE)); 538 } 539 540 @Test 541 @SdkSuppress(maxSdkVersion = 18) 542 public void testGetLoadState_returnsSuccess_pre19() { 543 assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCESS); 544 } 545 546 @Test 547 @SdkSuppress(minSdkVersion = 19) 548 public void testGetLoadState_returnsSuccessIfLoadSuccess() throws InterruptedException { 549 final WaitingDataLoader metadataLoader = new WaitingDataLoader(true /*success*/); 550 final Config config = new TestConfig(metadataLoader); 551 EmojiCompat.reset(config); 552 553 assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING); 554 555 metadataLoader.getLoaderLatch().countDown(); 556 metadataLoader.getTestLatch().await(); 557 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 558 559 assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCESS); 560 } 561 562 @Test 563 @SdkSuppress(minSdkVersion = 19) 564 public void testGetLoadState_returnsFailIfLoadFail() throws InterruptedException { 565 final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/); 566 final Config config = new TestConfig(metadataLoader); 567 EmojiCompat.reset(config); 568 569 assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING); 570 571 metadataLoader.getLoaderLatch().countDown(); 572 metadataLoader.getTestLatch().await(); 573 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 574 575 assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_FAILURE); 576 } 577 578 @Test 579 public void testUpdateEditorInfoAttrs_doesNotSetKeyIfNotInitialized() { 580 final EditorInfo editorInfo = new EditorInfo(); 581 editorInfo.extras = new Bundle(); 582 583 final WaitingDataLoader metadataLoader = new WaitingDataLoader(); 584 final Config config = new TestConfig(metadataLoader); 585 EmojiCompat.reset(config); 586 587 EmojiCompat.get().updateEditorInfoAttrs(editorInfo); 588 589 final Bundle extras = editorInfo.extras; 590 assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY)); 591 assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY)); 592 593 metadataLoader.getLoaderLatch().countDown(); 594 } 595 596 @Test 597 @SdkSuppress(minSdkVersion = 19) 598 public void testUpdateEditorInfoAttrs_setsKeysIfInitialized() { 599 final EditorInfo editorInfo = new EditorInfo(); 600 editorInfo.extras = new Bundle(); 601 Config config = new TestConfig().setReplaceAll(false); 602 EmojiCompat.reset(config); 603 EmojiCompat.get().updateEditorInfoAttrs(editorInfo); 604 605 final Bundle extras = editorInfo.extras; 606 assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY)); 607 assertTrue(extras.getInt(EmojiCompat.EDITOR_INFO_METAVERSION_KEY) > 0); 608 assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY)); 609 assertFalse(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY)); 610 611 config = new TestConfig().setReplaceAll(true); 612 EmojiCompat.reset(config); 613 EmojiCompat.get().updateEditorInfoAttrs(editorInfo); 614 615 assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY)); 616 assertTrue(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY)); 617 } 618 619 @Test 620 @SdkSuppress(maxSdkVersion = 18) 621 public void testHandleDeleteSurroundingText_pre19() { 622 final TestString testString = new TestString(EMOJI_SINGLE_CODEPOINT); 623 final InputConnection inputConnection = mock(InputConnection.class); 624 final Editable editable = spy(new SpannableStringBuilder(testString.toString())); 625 626 Selection.setSelection(editable, testString.emojiEndIndex()); 627 628 reset(editable); 629 reset(inputConnection); 630 verifyNoMoreInteractions(editable); 631 verifyNoMoreInteractions(inputConnection); 632 633 // try backwards delete 1 character 634 assertFalse( 635 EmojiCompat.handleDeleteSurroundingText(inputConnection, editable, 1, 0, false)); 636 } 637 638 @Test 639 @SdkSuppress(maxSdkVersion = 18) 640 public void testOnKeyDown_pre19() { 641 final TestString testString = new TestString(EMOJI_SINGLE_CODEPOINT); 642 final Editable editable = spy(new SpannableStringBuilder(testString.toString())); 643 Selection.setSelection(editable, testString.emojiEndIndex()); 644 final KeyEvent event = del(); 645 646 reset(editable); 647 verifyNoMoreInteractions(editable); 648 649 assertFalse(EmojiCompat.handleOnKeyDown(editable, event.getKeyCode(), event)); 650 } 651 652 private void assertCodePointMatch(EmojiMapping emoji) { 653 assertCodePointMatch(emoji.id(), emoji.codepoints()); 654 } 655 656 private void assertCodePointMatch(int id, int[] codepoints) { 657 TestString string = new TestString(codepoints); 658 CharSequence charSequence = EmojiCompat.get().process(string.toString()); 659 assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex())); 660 661 // case where Emoji is in the middle of string 662 string = new TestString(codepoints).withPrefix().withSuffix(); 663 charSequence = EmojiCompat.get().process(string.toString()); 664 assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex())); 665 666 // case where Emoji is at the end of string 667 string = new TestString(codepoints).withSuffix(); 668 charSequence = EmojiCompat.get().process(string.toString()); 669 assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex())); 670 } 671 672 private void assertCodePointDoesNotMatch(int[] codepoints) { 673 TestString string = new TestString(codepoints); 674 CharSequence charSequence = EmojiCompat.get().process(string.toString()); 675 assertThat(charSequence, not(hasEmoji())); 676 677 string = new TestString(codepoints).withSuffix().withPrefix(); 678 charSequence = EmojiCompat.get().process(string.toString()); 679 assertThat(charSequence, not(hasEmoji())); 680 681 string = new TestString(codepoints).withPrefix(); 682 charSequence = EmojiCompat.get().process(string.toString()); 683 assertThat(charSequence, not(hasEmoji())); 684 } 685 686 //FAILS: CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_VS_TEXT 687} 688