182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir *
482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License");
582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * you may not use this file except in compliance with the License.
682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * You may obtain a copy of the License at
782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir *
882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir *      http://www.apache.org/licenses/LICENSE-2.0
982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir *
1082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Unless required by applicable law or agreed to in writing, software
1182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS,
1282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * See the License for the specific language governing permissions and
1482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * limitations under the License.
1582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */
16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.emoji.text;
1782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
18ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.emoji.util.EmojiMatcher.hasEmojiAt;
19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.emoji.util.EmojiMatcher.hasEmojiCount;
2082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
2182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport static org.junit.Assert.assertThat;
22fa39e2bca1b284ad7c931d9194287770b7b507faAurimas Liutikasimport static org.junit.Assert.assertTrue;
2382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
2482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.content.Context;
25478b4ffdd939482869779da95c45b259771a620bSiyamed Sinirimport android.graphics.Paint;
2682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.test.InstrumentationRegistry;
279546df94e6393de504f7ef8dc1b12a1f550c47a8Siyamed Sinirimport android.support.test.filters.SdkSuppress;
2882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.test.filters.SmallTest;
29478b4ffdd939482869779da95c45b259771a620bSiyamed Sinirimport android.text.Spanned;
3082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
3138746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.core.graphics.PaintCompat;
3238746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.emoji.util.TestString;
3338746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikas
3482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.junit.BeforeClass;
3582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.junit.Test;
3682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.junit.runner.RunWith;
3782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.junit.runners.Parameterized;
3882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
3982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.io.BufferedReader;
4082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.io.IOException;
4182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.io.InputStream;
4282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.io.InputStreamReader;
4382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.util.ArrayList;
4482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.util.Collection;
4582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
4682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/**
4782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Reads raw/allemojis.txt which includes all the emojis known to human kind and tests that
4882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * EmojiCompat creates EmojiSpans for each one of them.
4982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */
5082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir@SmallTest
5182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir@RunWith(Parameterized.class)
529546df94e6393de504f7ef8dc1b12a1f550c47a8Siyamed Sinir@SdkSuppress(minSdkVersion = 19)
5382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirpublic class AllEmojisTest {
5482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
5582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    /**
5682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir     * String representation for a single emoji
5782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir     */
5882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    private String mString;
5982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
6082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    /**
6182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir     * Codepoints of emoji for better assert error message.
6282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir     */
6382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    private String mCodepoints;
6482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
65478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir    /**
66478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir     * Paint object used to check if Typeface can render the given emoji.
67478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir     */
68478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir    private Paint mPaint;
69478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir
7082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    @BeforeClass
7182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static void setup() {
7282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        EmojiCompat.reset(TestConfigBuilder.config());
7382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
7482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
7582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    @Parameterized.Parameters
76b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir    public static Collection<Object[]> data() throws IOException {
7782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        final Context context = InstrumentationRegistry.getTargetContext();
78176b7a517ad28a8cffc8cc3307b6ce2c42a36cc9Siyamed Sinir        final InputStream inputStream = context.getAssets().open("emojis.txt");
7982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        try {
80b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir            final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
81b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir            final Collection<Object[]> data = new ArrayList<>();
82b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir            final StringBuilder stringBuilder = new StringBuilder();
83b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir            final StringBuilder codePointsBuilder = new StringBuilder();
84b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir
8582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            String s;
8682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            while ((s = reader.readLine()) != null) {
87b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir                s = s.trim();
88b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir                // pass comments
89b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir                if (s.isEmpty() || s.startsWith("#")) continue;
90b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir
9182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                stringBuilder.setLength(0);
9282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                codePointsBuilder.setLength(0);
9382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
9482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                // emoji codepoints are space separated: i.e. 0x1f1e6 0x1f1e8
9582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                final String[] split = s.split(" ");
9682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
9782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                for (int index = 0; index < split.length; index++) {
98b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir                    final String part = split[index].trim();
99b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir                    codePointsBuilder.append(part);
10082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    codePointsBuilder.append(",");
101b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir                    stringBuilder.append(Character.toChars(Integer.parseInt(part, 16)));
10282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                }
10382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                data.add(new Object[]{stringBuilder.toString(), codePointsBuilder.toString()});
10482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
105b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir
106b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir            return data;
107b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir        } finally {
108b7b27782ff7589608ed7de38634adc846665cecbSiyamed Sinir            inputStream.close();
10982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
11082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
11182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
11282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
11382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public AllEmojisTest(String string, String codepoints) {
11482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        mString = string;
11582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        mCodepoints = codepoints;
116478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        mPaint = new Paint();
11782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
11882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
11982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    @Test
12082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public void testEmoji() {
12182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertTrue("EmojiCompat should have emoji: " + mCodepoints,
12282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                EmojiCompat.get().hasEmojiGlyph(mString));
12382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertEmojiCompatAddsEmoji(mString);
124478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        assertSpanCanRenderEmoji(mString);
125478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir    }
126478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir
127478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir    private void assertSpanCanRenderEmoji(final String str) {
128478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        final Spanned spanned = (Spanned) EmojiCompat.get().process(new TestString(str).toString());
129478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        final EmojiSpan[] spans = spanned.getSpans(0, spanned.length(), EmojiSpan.class);
130478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        final EmojiMetadata metadata = spans[0].getMetadata();
131478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        mPaint.setTypeface(metadata.getTypeface());
132478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir
133478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        final String codepoint = String.valueOf(Character.toChars(metadata.getId()));
134478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir        assertTrue(metadata.toString() + " should be rendered",
135478b4ffdd939482869779da95c45b259771a620bSiyamed Sinir                PaintCompat.hasGlyph(mPaint, codepoint));
13682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
13782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
13882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    private void assertEmojiCompatAddsEmoji(final String str) {
13982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        TestString string = new TestString(str);
14082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        CharSequence sequence = EmojiCompat.get().process(string.toString());
14182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertThat(sequence, hasEmojiCount(1));
14282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
14382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
14482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        // case where Emoji is in the middle of string
14582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        string = new TestString(str).withPrefix().withSuffix();
14682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        sequence = EmojiCompat.get().process(string.toString());
14782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertThat(sequence, hasEmojiCount(1));
14882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
14982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
15082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        // case where Emoji is at the end of string
15182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        string = new TestString(str).withSuffix();
15282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        sequence = EmojiCompat.get().process(string.toString());
15382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertThat(sequence, hasEmojiCount(1));
15482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        assertThat(sequence, hasEmojiAt(string.emojiStartIndex(), string.emojiEndIndex()));
15582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
15682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
15782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir}
158