chromium/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfContentProviderUnitTest.java

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.pdf;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;

import org.chromium.base.ContextUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class PdfContentProviderUnitTest {
    private static final String TEST_FILE_PATH = "/proc/5202/fd/344";
    private static final String TEST_FILE_NAME = "test_pdf.pdf";
    private PdfContentProvider mProvider;
    @Mock private Context mContext;

    @Before
    public void setUp() throws IOException {
        MockitoAnnotations.initMocks(this);
        mProvider = new PdfContentProvider();
        ContextUtils.initApplicationContextForTests(mContext);
        // Mock the package name for generating the URI
        when(mContext.getPackageName()).thenReturn("com.example.app");
    }

    @After
    public void tearDown() {
        // Ensure the test file is deleted
        PdfContentProvider.cleanUpForTesting();
    }

    @Test(expected = FileNotFoundException.class)
    public void testCreateAndRemoveContentUri() throws FileNotFoundException {
        Uri uri = PdfContentProvider.createContentUri(TEST_FILE_PATH, TEST_FILE_NAME);
        assertNotNull("Content URI should not be null", uri);
        assertTrue(
                "Content URI should have the correct authority",
                uri.getAuthority().endsWith(".PdfContentProvider"));
        PdfContentProvider.removeContentUri(uri.toString());
        mProvider.openFile(uri, "r");
    }

    @Test
    public void testCreateInvalidFilePath() throws FileNotFoundException {
        Uri uri = PdfContentProvider.createContentUri("/xyz/abc.pdf", TEST_FILE_NAME);
        assertNull(uri);
    }

    @Test
    public void testGetType() throws Exception {
        Uri uri = PdfContentProvider.createContentUri(TEST_FILE_PATH, TEST_FILE_NAME);
        String type = mProvider.getType(uri);
        assertEquals("Mime type should be application/pdf", "application/pdf", type);

        // Create another uri.
        Thread.sleep(1);
        Uri uri2 = PdfContentProvider.createContentUri(TEST_FILE_PATH, "xyzs");
        type = mProvider.getType(uri2);
        assertEquals("Mime type should be application/pdf", "application/pdf", type);
        assertNotEquals("Content Uris should be different", uri, uri2);
    }

    @Test
    public void testGetStreamTypes() {
        Uri uri = PdfContentProvider.createContentUri(TEST_FILE_PATH, TEST_FILE_NAME);
        String[] types = mProvider.getStreamTypes(uri, "*/*");
        assertNotNull("Stream types should not be null", types);
        assertEquals("There should be one stream type", 1, types.length);
        assertEquals("Stream type should be application/pdf", "application/pdf", types[0]);

        String[] types2 = mProvider.getStreamTypes(uri, "*/pdf");
        String[] types3 = mProvider.getStreamTypes(uri, "application/pdf");
        String[] types4 = mProvider.getStreamTypes(uri, "application/*");
        assertEquals(types2, types);
        assertEquals(types3, types);
        assertEquals(types4, types);

        assertNull(mProvider.getStreamTypes(uri, "*/pdfx"));
        assertNull(mProvider.getStreamTypes(uri, "image/jpg"));
    }

    @Test
    public void testOpenFile() throws FileNotFoundException {
        Uri uri = PdfContentProvider.createContentUri(TEST_FILE_PATH, TEST_FILE_NAME);
        File tempFile = createTempFile();
        PdfContentProvider.setPdfFileInfoForTesting(
                uri,
                new PdfContentProvider.PdfFileInfo(
                        TEST_FILE_PATH,
                        TEST_FILE_NAME,
                        ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY)));
        ParcelFileDescriptor pfd = mProvider.openFile(uri, "r");
        assertNotNull("ParcelFileDescriptor should not be null", pfd);
    }

    @Test(expected = FileNotFoundException.class)
    public void testOpenFile_FileNotFound() throws FileNotFoundException {
        mProvider.openFile(Uri.parse("content://nonexistent"), "r");
    }

    @Test
    public void testQuery() throws FileNotFoundException {
        Uri uri = PdfContentProvider.createContentUri(TEST_FILE_PATH, TEST_FILE_NAME);
        File tempFile = createTempFile();
        PdfContentProvider.setPdfFileInfoForTesting(
                uri,
                new PdfContentProvider.PdfFileInfo(
                        TEST_FILE_PATH,
                        TEST_FILE_NAME,
                        ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY)));

        Cursor cursor = mProvider.query(uri, null, null, null, null);
        assertNotNull("Cursor should not be null", cursor);
        assertTrue("Cursor should have results", cursor.moveToFirst());

        int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);

        assertFalse("Column indexes should be valid", nameIndex == -1 || sizeIndex == -1);
        assertEquals("File name should match", TEST_FILE_NAME, cursor.getString(nameIndex));
        assertTrue("File size should be greater than 0", cursor.getLong(sizeIndex) > 0);
    }

    private File createTempFile() {
        try {
            File tempFile = File.createTempFile("test_pdf", ".pdf");
            tempFile.deleteOnExit();
            FileOutputStream outputStream = new FileOutputStream(tempFile);
            outputStream.write(1234);
            return tempFile;
        } catch (IOException e) {
            fail("Cannot create temporary file.");
        }
        return null;
    }
}