Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06762053 authored by Hieu Dang's avatar Hieu Dang Committed by Gerrit Code Review
Browse files

Merge "Add BluetoothOppSendFileInfoTest"

parents a242bcc8 8d86ccba
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -34,6 +35,7 @@ import com.android.obex.HeaderSet;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Proxy class for method calls to help with unit testing
@@ -132,6 +134,23 @@ public class BluetoothMethodProxy {
        return contentResolver.openFileDescriptor(uri, mode);
    }

    /**
     * Proxies {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
     */
    public AssetFileDescriptor contentResolverOpenAssetFileDescriptor(
            ContentResolver contentResolver, final Uri uri, final String mode)
            throws FileNotFoundException {
        return contentResolver.openAssetFileDescriptor(uri, mode);
    }

    /**
     * Proxies {@link ContentResolver#openInputStream(Uri)}.
     */
    public InputStream contentResolverOpenInputStream(ContentResolver contentResolver,
            final Uri uri) throws FileNotFoundException {
        return contentResolver.openInputStream(uri);
    }

    /**
     * Proxies {@link Context#sendBroadcast(Intent)}.
     */
+13 −7
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.provider.OpenableColumns;
import android.util.EventLog;
import android.util.Log;

import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.R;

import java.io.File;
@@ -119,7 +120,8 @@ public class BluetoothOppSendFileInfo {
            contentType = contentResolver.getType(uri);
            Cursor metadataCursor;
            try {
                metadataCursor = contentResolver.query(uri, new String[]{
                metadataCursor = BluetoothMethodProxy.getInstance().contentResolverQuery(
                        contentResolver, uri, new String[]{
                                OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
                        }, null, null, null);
            } catch (SQLiteException e) {
@@ -180,7 +182,8 @@ public class BluetoothOppSendFileInfo {
                // right size in _OpenableColumns.SIZE
                // As a second source of getting the correct file length,
                // get a file descriptor and get the stat length
                AssetFileDescriptor fd = contentResolver.openAssetFileDescriptor(uri, "r");
                AssetFileDescriptor fd = BluetoothMethodProxy.getInstance()
                        .contentResolverOpenAssetFileDescriptor(contentResolver, uri, "r");
                long statLength = fd.getLength();
                if (length != statLength && statLength > 0) {
                    Log.e(TAG, "Content provider length is wrong (" + Long.toString(length)
@@ -200,7 +203,8 @@ public class BluetoothOppSendFileInfo {
                        length = getStreamSize(is);
                        Log.w(TAG, "File length not provided. Length from stream = " + length);
                        // Reset the stream
                        fd = contentResolver.openAssetFileDescriptor(uri, "r");
                        fd = BluetoothMethodProxy.getInstance()
                                .contentResolverOpenAssetFileDescriptor(contentResolver, uri, "r");
                        is = fd.createInputStream();
                    }
                } catch (IOException e) {
@@ -219,14 +223,16 @@ public class BluetoothOppSendFileInfo {

        if (is == null) {
            try {
                is = (FileInputStream) contentResolver.openInputStream(uri);
                is = (FileInputStream) BluetoothMethodProxy.getInstance()
                        .contentResolverOpenInputStream(contentResolver, uri);

                // If the database doesn't contain the file size, get the size
                // by reading through the entire stream
                if (length == 0) {
                    length = getStreamSize(is);
                    // Reset the stream
                    is = (FileInputStream) contentResolver.openInputStream(uri);
                    is = (FileInputStream) BluetoothMethodProxy.getInstance()
                            .contentResolverOpenInputStream(contentResolver, uri);
                }
            } catch (FileNotFoundException e) {
                return SEND_FILE_INFO_ERROR;
+220 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.android.bluetooth.opp;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.util.Log;

import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.BluetoothMethodProxy;

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 java.io.FileInputStream;
import java.io.IOException;

@RunWith(AndroidJUnit4.class)
public class BluetoothOppSendFileInfoTest {
    Context mContext;
    MatrixCursor mCursor;

    @Mock
    BluetoothMethodProxy mCallProxy;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        BluetoothMethodProxy.setInstanceForTesting(mCallProxy);
    }

    @After
    public void tearDown() {
        BluetoothMethodProxy.setInstanceForTesting(null);
    }

    @Test
    public void createInstance_withFileInputStream() {
        String fileName = "abc.txt";
        String type = "text/plain";
        long length = 10000;
        FileInputStream inputStream = mock(FileInputStream.class);
        int status = BluetoothShare.STATUS_SUCCESS;
        BluetoothOppSendFileInfo info =
                new BluetoothOppSendFileInfo(fileName, type, length, inputStream, status);

        assertThat(info.mStatus).isEqualTo(status);
        assertThat(info.mFileName).isEqualTo(fileName);
        assertThat(info.mLength).isEqualTo(length);
        assertThat(info.mInputStream).isEqualTo(inputStream);
        assertThat(info.mMimetype).isEqualTo(type);
    }

    @Test
    public void createInstance_withoutFileInputStream() {
        String type = "text/plain";
        long length = 10000;
        int status = BluetoothShare.STATUS_SUCCESS;
        String data = "Testing is boring";
        BluetoothOppSendFileInfo info =
                new BluetoothOppSendFileInfo(data, type, length, status);

        assertThat(info.mStatus).isEqualTo(status);
        assertThat(info.mData).isEqualTo(data);
        assertThat(info.mLength).isEqualTo(length);
        assertThat(info.mMimetype).isEqualTo(type);
    }

    @Test
    public void generateFileInfo_withUnsupportedScheme_returnsSendFileInfoError() {
        String type = "text/plain";
        Uri uri = Uri.parse("https://www.google.com");

        BluetoothOppSendFileInfo info = BluetoothOppSendFileInfo.generateFileInfo(mContext, uri,
                type, true);
        assertThat(info).isEqualTo(BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
    }

    @Test
    public void generateFileInfo_withForbiddenExternalUri_returnsSendFileInfoError() {
        String type = "text/plain";
        Uri uri = Uri.parse("content://com.android.bluetooth.map.MmsFileProvider:8080");

        BluetoothOppSendFileInfo info = BluetoothOppSendFileInfo.generateFileInfo(mContext, uri,
                type, true);
        assertThat(info).isEqualTo(BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
    }

    @Test
    public void generateFileInfo_withoutPermissionForAccessingUri_returnsSendFileInfoError() {
        String type = "text/plain";
        Uri uri = Uri.parse("content:///hello/world");

        doThrow(new SecurityException()).when(mCallProxy).contentResolverQuery(
                any(), eq(uri), any(), any(), any(),
                any());

        BluetoothOppSendFileInfo info = BluetoothOppSendFileInfo.generateFileInfo(mContext, uri,
                type, true);
        assertThat(info).isEqualTo(BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
    }

    @Test
    public void generateFileInfo_withUncorrectableMismatch_returnsSendFileInfoError()
            throws IOException {
        String type = "text/plain";
        Uri uri = Uri.parse("content:///hello/world");

        long fileLength = 0;
        String fileName = "coolName.txt";

        AssetFileDescriptor fd = mock(AssetFileDescriptor.class);
        FileInputStream fs = mock(FileInputStream.class);

        mCursor = new MatrixCursor(new String[]{
                OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
        });
        mCursor.addRow(new Object[]{fileName, fileLength});

        doReturn(mCursor).when(mCallProxy).contentResolverQuery(
                any(), eq(uri), any(), any(), any(),
                any());

        doReturn(fd).when(mCallProxy).contentResolverOpenAssetFileDescriptor(
                any(), eq(uri), any());
        doReturn(0L).when(fd).getLength();
        doThrow(new IOException()).when(fd).createInputStream();
        doReturn(fs).when(mCallProxy).contentResolverOpenInputStream(any(), eq(uri));
        doReturn(0, -1).when(fs).read(any(), anyInt(), anyInt());

        BluetoothOppSendFileInfo info = BluetoothOppSendFileInfo.generateFileInfo(mContext, uri,
                type, true);

        assertThat(info).isEqualTo(BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
    }

    @Test
    public void generateFileInfo_withCorrectableMismatch_returnInfoWithCorrectLength()
            throws IOException {
        String type = "text/plain";
        Uri uri = Uri.parse("content:///hello/world");

        long fileLength = 0;
        long correctFileLength = 1000;
        String fileName = "coolName.txt";

        AssetFileDescriptor fd = mock(AssetFileDescriptor.class);
        FileInputStream fs = mock(FileInputStream.class);

        mCursor = new MatrixCursor(new String[]{
                OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
        });
        mCursor.addRow(new Object[]{fileName, fileLength});

        doReturn(mCursor).when(mCallProxy).contentResolverQuery(
                any(), eq(uri), any(), any(), any(),
                any());

        doReturn(fd).when(mCallProxy).contentResolverOpenAssetFileDescriptor(
                any(), eq(uri), any());
        doReturn(0L).when(fd).getLength();
        doReturn(fs).when(fd).createInputStream();

        // the real size will be returned in getStreamSize(fs)
        doReturn((int) correctFileLength, -1).when(fs).read(any(), anyInt(), anyInt());

        BluetoothOppSendFileInfo info = BluetoothOppSendFileInfo.generateFileInfo(mContext, uri,
                type, true);

        assertThat(info.mInputStream).isEqualTo(fs);
        assertThat(info.mFileName).isEqualTo(fileName);
        assertThat(info.mLength).isEqualTo(correctFileLength);
        assertThat(info.mStatus).isEqualTo(0);
    }

    @Test
    public void generateFileInfo_withFileUriNotInExternalStorageDir_returnFileErrorInfo() {
        String type = "text/plain";
        Uri uri = Uri.parse("file:///obviously/not/in/external/storage");

        BluetoothOppSendFileInfo info = BluetoothOppSendFileInfo.generateFileInfo(mContext, uri,
                type, true);

        assertThat(info).isEqualTo(BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
    }
}