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.provider;
17
18import static org.mockito.Matchers.anyInt;
19import static org.mockito.Matchers.anyString;
20import static org.mockito.Mockito.mock;
21import static org.mockito.Mockito.when;
22
23import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
24import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
25import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
26import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
27
28import android.content.pm.ApplicationInfo;
29import android.content.pm.PackageInfo;
30import android.content.pm.PackageManager.NameNotFoundException;
31import android.content.pm.PackageManager;
32import android.content.pm.ProviderInfo;
33import android.content.pm.Signature;
34import android.database.MatrixCursor;
35import android.graphics.fonts.FontVariationAxis;
36import android.provider.FontsContract.FontInfo;
37import android.support.test.filters.SmallTest;
38import android.test.ProviderTestCase2;
39import android.util.Base64;
40
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.List;
44
45/**
46 * Unit tests for {@link FontsContract}.
47 */
48@SmallTest
49public class FontsContractTest extends ProviderTestCase2<TestFontsProvider> {
50    private static final byte[] BYTE_ARRAY =
51            Base64.decode("e04fd020ea3a6910a2d808002b30", Base64.DEFAULT);
52    // Use a different instance to test byte array comparison
53    private static final byte[] BYTE_ARRAY_COPY =
54            Base64.decode("e04fd020ea3a6910a2d808002b30", Base64.DEFAULT);
55    private static final byte[] BYTE_ARRAY_2 =
56            Base64.decode("e04fd020ea3a6910a2d808002b32", Base64.DEFAULT);
57    private static final String PACKAGE_NAME = "com.my.font.provider.package";
58
59    private final FontRequest request = new FontRequest(
60            TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query");
61    private TestFontsProvider mProvider;
62    private PackageManager mPackageManager;
63
64    public FontsContractTest() {
65        super(TestFontsProvider.class, TestFontsProvider.AUTHORITY);
66    }
67
68    public void setUp() throws Exception {
69        super.setUp();
70
71        mProvider = getProvider();
72        mPackageManager = mock(PackageManager.class);
73    }
74
75    public void testGetFontFromProvider_resultOK() {
76        FontInfo[] fonts = FontsContract.getFontFromProvider(
77                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
78        assertNotNull(fonts);
79        assertEquals(1, fonts.length);
80        FontInfo font = fonts[0];
81        assertEquals(TestFontsProvider.TTC_INDEX, font.getTtcIndex());
82        FontVariationAxis[] actual = font.getAxes();
83        assertEquals(1, actual.length);
84        assertEquals("wdth", actual[0].getTag());
85        assertEquals(1.0f, actual[0].getStyleValue(), 0);
86        assertEquals(TestFontsProvider.NORMAL_WEIGHT, font.getWeight());
87        assertEquals(TestFontsProvider.ITALIC, font.isItalic());
88        assertNotNull(font.getUri());
89        assertEquals(RESULT_CODE_OK, font.getResultCode());
90    }
91
92    public void testGetFontFromProvider_providerDoesntReturnAllFields() {
93        mProvider.setReturnAllFields(false);
94
95        FontInfo[] fonts = FontsContract.getFontFromProvider(
96                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
97        assertNotNull(fonts);
98        assertEquals(1, fonts.length);
99        FontInfo font = fonts[0];
100        assertEquals(0, font.getTtcIndex());
101        assertNull(font.getAxes());
102        assertEquals(400, font.getWeight());
103        assertFalse(font.isItalic());
104        assertNotNull(font.getUri());
105        assertEquals(RESULT_CODE_OK, font.getResultCode());
106    }
107
108    public void testGetFontFromProvider_resultFontNotFound() {
109        // Make the provider return unknown
110        mProvider.setResultCode(RESULT_CODE_FONT_NOT_FOUND);
111        FontInfo[] fonts = FontsContract.getFontFromProvider(
112                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
113        assertNotNull(fonts);
114        assertEquals(1, fonts.length);
115        FontInfo font = fonts[0];
116        assertEquals(TestFontsProvider.TTC_INDEX, font.getTtcIndex());
117        assertNotNull(font.getUri());
118        assertEquals(RESULT_CODE_FONT_NOT_FOUND, font.getResultCode());
119    }
120
121    public void testGetFontFromProvider_resultFontUnavailable() {
122        // Make the provider return font unavailable
123        mProvider.setResultCode(RESULT_CODE_FONT_UNAVAILABLE);
124        FontInfo[] fonts = FontsContract.getFontFromProvider(
125                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
126
127        assertNotNull(fonts);
128        assertEquals(1, fonts.length);
129        FontInfo font = fonts[0];
130        assertEquals(TestFontsProvider.TTC_INDEX, font.getTtcIndex());
131        FontVariationAxis[] actual = font.getAxes();
132        assertEquals(1, actual.length);
133        assertEquals("wdth", actual[0].getTag());
134        assertEquals(1.0f, actual[0].getStyleValue(), 0);
135        assertEquals(TestFontsProvider.NORMAL_WEIGHT, font.getWeight());
136        assertEquals(TestFontsProvider.ITALIC, font.isItalic());
137        assertNotNull(font.getUri());
138        assertEquals(RESULT_CODE_FONT_UNAVAILABLE, font.getResultCode());
139    }
140
141    public void testGetFontFromProvider_resultMalformedQuery() {
142        // Make the provider return font unavailable
143        mProvider.setResultCode(RESULT_CODE_MALFORMED_QUERY);
144        FontInfo[] fonts = FontsContract.getFontFromProvider(
145                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
146
147        assertNotNull(fonts);
148        assertEquals(1, fonts.length);
149        FontInfo font = fonts[0];
150        assertEquals(TestFontsProvider.TTC_INDEX, font.getTtcIndex());
151        FontVariationAxis[] actual = font.getAxes();
152        assertEquals(1, actual.length);
153        assertEquals("wdth", actual[0].getTag());
154        assertEquals(1.0f, actual[0].getStyleValue(), 0);
155        assertEquals(TestFontsProvider.NORMAL_WEIGHT, font.getWeight());
156        assertEquals(TestFontsProvider.ITALIC, font.isItalic());
157        assertNotNull(font.getUri());
158        assertEquals(RESULT_CODE_MALFORMED_QUERY, font.getResultCode());
159    }
160
161    public void testGetFontFromProvider_resultFontNotFoundSecondRow() {
162        MatrixCursor cursor = new MatrixCursor(new String[] { FontsContract.Columns._ID,
163                FontsContract.Columns.TTC_INDEX, FontsContract.Columns.VARIATION_SETTINGS,
164                FontsContract.Columns.WEIGHT, FontsContract.Columns.ITALIC,
165                FontsContract.Columns.RESULT_CODE });
166        cursor.addRow(new Object[] { 1, 0, null, 400, 0, RESULT_CODE_OK});
167        cursor.addRow(new Object[] { 1, 0, null, 400, 0,
168                RESULT_CODE_FONT_NOT_FOUND});
169        mProvider.setCustomCursor(cursor);
170        FontInfo[] fonts = FontsContract.getFontFromProvider(
171                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
172
173        assertNotNull(fonts);
174        assertEquals(2, fonts.length);
175
176        FontInfo font = fonts[0];
177        assertEquals(0, font.getTtcIndex());
178        assertNull(font.getAxes());
179        assertEquals(400, font.getWeight());
180        assertFalse(font.isItalic());
181        assertNotNull(font.getUri());
182        assertEquals(RESULT_CODE_OK, font.getResultCode());
183
184        font = fonts[1];
185        assertEquals(0, font.getTtcIndex());
186        assertNull(font.getAxes());
187        assertEquals(400, font.getWeight());
188        assertFalse(font.isItalic());
189        assertNotNull(font.getUri());
190        assertEquals(RESULT_CODE_FONT_NOT_FOUND, font.getResultCode());
191    }
192
193    public void testGetFontFromProvider_resultFontNotFoundOtherRow() {
194        MatrixCursor cursor = new MatrixCursor(new String[] { FontsContract.Columns._ID,
195                FontsContract.Columns.TTC_INDEX, FontsContract.Columns.VARIATION_SETTINGS,
196                FontsContract.Columns.WEIGHT, FontsContract.Columns.ITALIC,
197                FontsContract.Columns.RESULT_CODE });
198        cursor.addRow(new Object[] { 1, 0, null, 400, 0, RESULT_CODE_OK});
199        cursor.addRow(new Object[] { 1, 0, null, 400, 0,
200                RESULT_CODE_FONT_NOT_FOUND});
201        cursor.addRow(new Object[] { 1, 0, null, 400, 0, RESULT_CODE_OK});
202        mProvider.setCustomCursor(cursor);
203        FontInfo[] fonts = FontsContract.getFontFromProvider(
204                getMockContext(), request, TestFontsProvider.AUTHORITY, null);
205
206        assertNotNull(fonts);
207        assertEquals(3, fonts.length);
208
209        FontInfo font = fonts[0];
210        assertEquals(0, font.getTtcIndex());
211        assertNull(font.getAxes());
212        assertEquals(400, font.getWeight());
213        assertFalse(font.isItalic());
214        assertNotNull(font.getUri());
215        assertEquals(RESULT_CODE_OK, font.getResultCode());
216
217        font = fonts[1];
218        assertEquals(0, font.getTtcIndex());
219        assertNull(font.getAxes());
220        assertEquals(400, font.getWeight());
221        assertFalse(font.isItalic());
222        assertNotNull(font.getUri());
223        assertEquals(RESULT_CODE_FONT_NOT_FOUND, font.getResultCode());
224
225        font = fonts[2];
226        assertEquals(0, font.getTtcIndex());
227        assertNull(font.getAxes());
228        assertEquals(400, font.getWeight());
229        assertFalse(font.isItalic());
230        assertNotNull(font.getUri());
231        assertEquals(RESULT_CODE_OK, font.getResultCode());
232    }
233
234    public void testGetProvider_providerNotFound() {
235        when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(null);
236
237        try {
238            FontsContract.getProvider(mPackageManager, request);
239            fail();
240        } catch (NameNotFoundException e) {
241            // pass
242        }
243    }
244
245    public void testGetProvider_providerIsSystemApp() throws PackageManager.NameNotFoundException {
246        ProviderInfo info = setupPackageManager();
247        info.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
248        when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
249
250        ProviderInfo result = FontsContract.getProvider(mPackageManager, request);
251        assertEquals(info, result);
252    }
253
254    public void testGetProvider_providerIsSystemAppWrongPackage()
255            throws PackageManager.NameNotFoundException {
256        ProviderInfo info = setupPackageManager();
257        info.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
258        when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
259
260        try {
261            FontsContract.getProvider(
262                mPackageManager,
263                new FontRequest(TestFontsProvider.AUTHORITY, "com.wrong.package", "query"));
264            fail();
265        } catch (NameNotFoundException e) {
266            // pass
267        }
268
269    }
270
271    public void testGetProvider_providerIsNonSystemAppNoCerts()
272            throws PackageManager.NameNotFoundException {
273        setupPackageManager();
274
275        assertNull(FontsContract.getProvider(mPackageManager, request));
276    }
277
278    public void testGetProvider_providerIsNonSystemAppWrongCerts()
279            throws PackageManager.NameNotFoundException {
280        setupPackageManager();
281
282        byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
283        List<byte[]> certList = Arrays.asList(wrongCert);
284        FontRequest requestWrongCerts = new FontRequest(
285                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
286
287        assertNull(FontsContract.getProvider(mPackageManager, requestWrongCerts));
288    }
289
290    public void testGetProvider_providerIsNonSystemAppCorrectCerts()
291            throws PackageManager.NameNotFoundException {
292        ProviderInfo info = setupPackageManager();
293
294        List<byte[]> certList = Arrays.asList(BYTE_ARRAY);
295        FontRequest requestRightCerts = new FontRequest(
296                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
297        ProviderInfo result = FontsContract.getProvider(
298                mPackageManager, requestRightCerts);
299
300        assertEquals(info, result);
301    }
302
303    public void testGetProvider_providerIsNonSystemAppMoreCerts()
304            throws PackageManager.NameNotFoundException {
305        setupPackageManager();
306
307        byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
308        List<byte[]> certList = Arrays.asList(wrongCert, BYTE_ARRAY);
309        FontRequest requestRightCerts = new FontRequest(
310                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
311        assertNull(FontsContract.getProvider(mPackageManager, requestRightCerts));
312    }
313
314    public void testGetProvider_providerIsNonSystemAppDuplicateCerts()
315            throws PackageManager.NameNotFoundException {
316        ProviderInfo info = new ProviderInfo();
317        info.packageName = PACKAGE_NAME;
318        info.applicationInfo = new ApplicationInfo();
319        when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
320        PackageInfo packageInfo = new PackageInfo();
321        Signature signature = mock(Signature.class);
322        when(signature.toByteArray()).thenReturn(BYTE_ARRAY_COPY);
323        Signature signature2 = mock(Signature.class);
324        when(signature2.toByteArray()).thenReturn(BYTE_ARRAY_COPY);
325        packageInfo.packageName = PACKAGE_NAME;
326        packageInfo.signatures = new Signature[] { signature, signature2 };
327        when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
328
329        // The provider has {BYTE_ARRAY_COPY, BYTE_ARRAY_COPY}, the request has
330        // {BYTE_ARRAY_2, BYTE_ARRAY_COPY}.
331        List<byte[]> certList = Arrays.asList(BYTE_ARRAY_2, BYTE_ARRAY_COPY);
332        FontRequest requestRightCerts = new FontRequest(
333                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
334        assertNull(FontsContract.getProvider(mPackageManager, requestRightCerts));
335    }
336
337    public void testGetProvider_providerIsNonSystemAppCorrectCertsSeveralSets()
338            throws PackageManager.NameNotFoundException {
339        ProviderInfo info = setupPackageManager();
340
341        List<List<byte[]>> certList = new ArrayList<>();
342        byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
343        certList.add(Arrays.asList(wrongCert));
344        certList.add(Arrays.asList(BYTE_ARRAY));
345        FontRequest requestRightCerts = new FontRequest(
346                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", certList);
347        ProviderInfo result = FontsContract.getProvider(mPackageManager, requestRightCerts);
348
349        assertEquals(info, result);
350    }
351
352    public void testGetProvider_providerIsNonSystemAppWrongPackage()
353            throws PackageManager.NameNotFoundException {
354        setupPackageManager();
355
356        List<List<byte[]>> certList = new ArrayList<>();
357        certList.add(Arrays.asList(BYTE_ARRAY));
358        FontRequest requestRightCerts = new FontRequest(
359                TestFontsProvider.AUTHORITY, "com.wrong.package.name", "query", certList);
360        try {
361            FontsContract.getProvider(mPackageManager, requestRightCerts);
362            fail();
363        } catch (NameNotFoundException e) {
364            // pass
365        }
366    }
367
368    private ProviderInfo setupPackageManager()
369            throws PackageManager.NameNotFoundException {
370        ProviderInfo info = new ProviderInfo();
371        info.packageName = PACKAGE_NAME;
372        info.applicationInfo = new ApplicationInfo();
373        when(mPackageManager.resolveContentProvider(anyString(), anyInt())).thenReturn(info);
374        PackageInfo packageInfo = new PackageInfo();
375        Signature signature = mock(Signature.class);
376        when(signature.toByteArray()).thenReturn(BYTE_ARRAY_COPY);
377        packageInfo.packageName = PACKAGE_NAME;
378        packageInfo.signatures = new Signature[] { signature };
379        when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
380        return info;
381    }
382}
383