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

Commit dd197794 authored by Sungsoo Lim's avatar Sungsoo Lim Committed by Automerger Merge Worker
Browse files

Merge "Add BluetoothOppSendFileInfoTest" into tm-qpr-dev am: 25a1acfb

parents 99976a42 25a1acfb
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);
    }
}