blob: 8dbe9456108f6ace49bb303572d33530387c819d [file] [log] [blame]
/*
* 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 com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.opp.BluetoothOppTestUtils.CursorMockData;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
public class BluetoothOppUtilityTest {
private static final Uri CORRECT_FORMAT_BUT_INVALID_FILE_URI = Uri.parse(
"content://com.android.bluetooth.opp/btopp/0123455343467");
private static final Uri INCORRECT_FORMAT_URI = Uri.parse("www.google.com");
Context mContext;
@Mock
Cursor mCursor;
@Spy
BluetoothMethodProxy mCallProxy = BluetoothMethodProxy.getInstance();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
BluetoothMethodProxy.setInstanceForTesting(mCallProxy);
}
@After
public void tearDown() {
BluetoothMethodProxy.setInstanceForTesting(null);
}
@Test
public void isBluetoothShareUri_correctlyCheckUri() {
assertThat(BluetoothOppUtility.isBluetoothShareUri(INCORRECT_FORMAT_URI)).isFalse();
assertThat(BluetoothOppUtility.isBluetoothShareUri(CORRECT_FORMAT_BUT_INVALID_FILE_URI))
.isTrue();
}
@Test
public void queryRecord_withInvalidFileUrl_returnsNull() {
doReturn(null).when(mCallProxy).contentResolverQuery(any(),
eq(CORRECT_FORMAT_BUT_INVALID_FILE_URI), eq(null), eq(null),
eq(null), eq(null));
assertThat(BluetoothOppUtility.queryRecord(mContext,
CORRECT_FORMAT_BUT_INVALID_FILE_URI)).isNull();
}
@Test
public void queryRecord_mockCursor_returnsInstance() {
String destinationValue = "AA:BB:CC:00:11:22";
doReturn(mCursor).when(mCallProxy).contentResolverQuery(any(),
eq(CORRECT_FORMAT_BUT_INVALID_FILE_URI), eq(null), eq(null),
eq(null), eq(null));
doReturn(true).when(mCursor).moveToFirst();
doReturn(destinationValue).when(mCursor).getString(anyInt());
assertThat(BluetoothOppUtility.queryRecord(mContext,
CORRECT_FORMAT_BUT_INVALID_FILE_URI)).isInstanceOf(BluetoothOppTransferInfo.class);
}
@Test
public void queryTransfersInBatch_returnsCorrectUrlArrayList() {
long timestampValue = 123456;
String where = BluetoothShare.TIMESTAMP + " == " + timestampValue;
AtomicInteger cnt = new AtomicInteger(1);
doReturn(mCursor).when(mCallProxy).contentResolverQuery(any(),
eq(BluetoothShare.CONTENT_URI), eq(new String[]{
BluetoothShare._DATA
}), eq(where), eq(null), eq(BluetoothShare._ID));
doAnswer(invocation -> cnt.incrementAndGet() > 5).when(mCursor).isAfterLast();
doReturn(CORRECT_FORMAT_BUT_INVALID_FILE_URI.toString()).when(mCursor)
.getString(0);
ArrayList<String> answer = BluetoothOppUtility.queryTransfersInBatch(mContext,
timestampValue);
for (String url : answer) {
assertThat(url).isEqualTo(CORRECT_FORMAT_BUT_INVALID_FILE_URI.toString());
}
}
@Test
public void openReceivedFile_fileNotExist() {
Uri contentResolverUri = Uri.parse("content://com.android.bluetooth.opp/btopp/0123");
Uri fileUri = Uri.parse("content:///tmp/randomFileName.txt");
Context spiedContext = spy(new ContextWrapper(mContext));
doReturn(mCursor).when(mCallProxy).contentResolverQuery(any(),
eq(contentResolverUri), any(), eq(null),
eq(null), eq(null));
doReturn(true).when(mCursor).moveToFirst();
doReturn(fileUri.toString()).when(mCursor).getString(anyInt());
BluetoothOppUtility.openReceivedFile(spiedContext, "randomFileName.txt",
"text/plain", 0L, contentResolverUri);
verify(spiedContext).startActivity(argThat(argument
-> Objects.equals(argument.getComponent().getClassName(),
BluetoothOppBtErrorActivity.class.getName())
));
}
@Test
public void openReceivedFile_fileExist_HandlingApplicationExist() throws FileNotFoundException {
Uri contentResolverUri = Uri.parse("content://com.android.bluetooth.opp/btopp/0123");
Uri fileUri = Uri.parse("content:///tmp/randomFileName.txt");
Context spiedContext = spy(new ContextWrapper(mContext));
// Control BluetoothOppUtility#fileExists flow
doReturn(mCursor).when(mCallProxy).contentResolverQuery(any(),
eq(contentResolverUri), any(), eq(null),
eq(null), eq(null));
doReturn(true).when(mCursor).moveToFirst();
doReturn(fileUri.toString()).when(mCursor).getString(anyInt());
doReturn(0).when(mCallProxy).contentResolverDelete(any(), any(), any(), any());
doReturn(null).when(mCallProxy).contentResolverOpenFileDescriptor(any(),
eq(fileUri), any());
// Control BluetoothOppUtility#isRecognizedFileType flow
PackageManager mockManager = mock(PackageManager.class);
doReturn(mockManager).when(spiedContext).getPackageManager();
doReturn(List.of(new ResolveInfo())).when(mockManager).queryIntentActivities(any(),
anyInt());
BluetoothOppUtility.openReceivedFile(spiedContext, "randomFileName.txt",
"text/plain", 0L, contentResolverUri);
verify(spiedContext).startActivity(argThat(argument
-> Objects.equals(
argument.getData(), Uri.parse("content:///tmp/randomFileName.txt")
) && Objects.equals(argument.getAction(), Intent.ACTION_VIEW)
));
}
@Test
public void openReceivedFile_fileExist_HandlingApplicationNotExist()
throws FileNotFoundException {
Uri contentResolverUri = Uri.parse("content://com.android.bluetooth.opp/btopp/0123");
Uri fileUri = Uri.parse("content:///tmp/randomFileName.txt");
Context spiedContext = spy(new ContextWrapper(mContext));
// Control BluetoothOppUtility#fileExists flow
doReturn(mCursor).when(mCallProxy).contentResolverQuery(any(),
eq(contentResolverUri), any(), eq(null),
eq(null), eq(null));
doReturn(true).when(mCursor).moveToFirst();
doReturn(fileUri.toString()).when(mCursor).getString(anyInt());
doReturn(0).when(mCallProxy).contentResolverDelete(any(), any(), any(), any());
doReturn(null).when(mCallProxy).contentResolverOpenFileDescriptor(any(),
eq(fileUri), any());
// Control BluetoothOppUtility#isRecognizedFileType flow
PackageManager mockManager = mock(PackageManager.class);
doReturn(mockManager).when(spiedContext).getPackageManager();
doReturn(List.of()).when(mockManager).queryIntentActivities(any(), anyInt());
BluetoothOppUtility.openReceivedFile(spiedContext, "randomFileName.txt",
"text/plain", 0L, contentResolverUri);
verify(spiedContext).startActivity(
argThat(argument -> argument.getComponent().getClassName().equals(
BluetoothOppBtErrorActivity.class.getName())
));
}
@Test
public void fillRecord_filledAllProperties() {
int idValue = 1234;
int directionValue = BluetoothShare.DIRECTION_OUTBOUND;
long totalBytesValue = 10;
long currentBytesValue = 1;
int statusValue = BluetoothShare.STATUS_PENDING;
Long timestampValue = 123456789L;
String destinationValue = "AA:BB:CC:00:11:22";
String fileNameValue = "Unknown file";
String deviceNameValue = "Unknown device"; // bt device name
String fileTypeValue = "text/plain";
List<CursorMockData> cursorMockDataList = List.of(
new CursorMockData(BluetoothShare._ID, 0, idValue),
new CursorMockData(BluetoothShare.STATUS, 1, statusValue),
new CursorMockData(BluetoothShare.DIRECTION, 2, directionValue),
new CursorMockData(BluetoothShare.TOTAL_BYTES, 3, totalBytesValue),
new CursorMockData(BluetoothShare.CURRENT_BYTES, 4, currentBytesValue),
new CursorMockData(BluetoothShare.TIMESTAMP, 5, timestampValue),
new CursorMockData(BluetoothShare.DESTINATION, 6, destinationValue),
new CursorMockData(BluetoothShare._DATA, 7, null),
new CursorMockData(BluetoothShare.FILENAME_HINT, 8, null),
new CursorMockData(BluetoothShare.MIMETYPE, 9, fileTypeValue)
);
BluetoothOppTestUtils.setUpMockCursor(mCursor, cursorMockDataList);
BluetoothOppTransferInfo info = new BluetoothOppTransferInfo();
BluetoothOppUtility.fillRecord(mContext, mCursor, info);
assertThat(info.mID).isEqualTo(idValue);
assertThat(info.mStatus).isEqualTo(statusValue);
assertThat(info.mDirection).isEqualTo(directionValue);
assertThat(info.mTotalBytes).isEqualTo(totalBytesValue);
assertThat(info.mCurrentBytes).isEqualTo(currentBytesValue);
assertThat(info.mTimeStamp).isEqualTo(timestampValue);
assertThat(info.mDestAddr).isEqualTo(destinationValue);
assertThat(info.mFileUri).isEqualTo(null);
assertThat(info.mFileType).isEqualTo(fileTypeValue);
assertThat(info.mDeviceName).isEqualTo(deviceNameValue);
assertThat(info.mHandoverInitiated).isEqualTo(false);
assertThat(info.mFileName).isEqualTo(fileNameValue);
}
@Test
public void fileExists_returnFalse() {
assertThat(
BluetoothOppUtility.fileExists(mContext, CORRECT_FORMAT_BUT_INVALID_FILE_URI)
).isFalse();
}
@Test
public void isRecognizedFileType_withWrongFileUriAndMimeType_returnFalse() {
assertThat(
BluetoothOppUtility.isRecognizedFileType(mContext,
CORRECT_FORMAT_BUT_INVALID_FILE_URI,
"aWrongMimeType")
).isFalse();
}
@Test
public void formatProgressText() {
assertThat(BluetoothOppUtility.formatProgressText(100, 42)).isEqualTo("42%");
}
@Test
public void formatResultText() {
assertThat(BluetoothOppUtility.formatResultText(1, 2, mContext)).isEqualTo(
"1 successful, 2 unsuccessful.");
}
@Test
public void getStatusDescription_returnCorrectString() {
String deviceName = "randomName";
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_PENDING, deviceName)).isEqualTo(
"File transfer not started yet.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_RUNNING, deviceName)).isEqualTo(
"File transfer is ongoing.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_SUCCESS, deviceName)).isEqualTo(
"File transfer completed successfully.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_NOT_ACCEPTABLE, deviceName)).isEqualTo(
"Content isn\'t supported.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_FORBIDDEN, deviceName)).isEqualTo(
"Transfer forbidden by target device.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_CANCELED, deviceName)).isEqualTo(
"Transfer canceled by user.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_FILE_ERROR, deviceName)).isEqualTo("Storage issue.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_CONNECTION_ERROR, deviceName)).isEqualTo(
"Connection unsuccessful.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_ERROR_NO_SDCARD, deviceName)).isEqualTo(
BluetoothOppUtility.deviceHasNoSdCard() ?
"No USB storage." :
"No SD card. Insert an SD card to save transferred files."
);
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_ERROR_SDCARD_FULL, deviceName)).isEqualTo(
BluetoothOppUtility.deviceHasNoSdCard() ?
"There isn\'t enough space in USB storage to save the file." :
"There isn\'t enough space on the SD card to save the file."
);
assertThat(BluetoothOppUtility.getStatusDescription(mContext,
BluetoothShare.STATUS_BAD_REQUEST, deviceName)).isEqualTo(
"Request can\'t be handled correctly.");
assertThat(BluetoothOppUtility.getStatusDescription(mContext, 12345465,
deviceName)).isEqualTo("Unknown error.");
}
@Test
public void originalUri_trimBeforeAt() {
Uri originalUri = Uri.parse("com.android.bluetooth.opp.BluetoothOppSendFileInfo");
Uri uri = Uri.parse("com.android.bluetooth.opp.BluetoothOppSendFileInfo@dfe15a6");
assertThat(BluetoothOppUtility.originalUri(uri)).isEqualTo(originalUri);
}
@Test
public void fileInfo_testFileInfoFunctions() {
assertThat(
BluetoothOppUtility.getSendFileInfo(CORRECT_FORMAT_BUT_INVALID_FILE_URI)
).isEqualTo(
BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR
);
assertThat(BluetoothOppUtility.generateUri(CORRECT_FORMAT_BUT_INVALID_FILE_URI,
BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR).toString()
).contains(
CORRECT_FORMAT_BUT_INVALID_FILE_URI.toString());
try {
BluetoothOppUtility.putSendFileInfo(CORRECT_FORMAT_BUT_INVALID_FILE_URI,
BluetoothOppSendFileInfo.SEND_FILE_INFO_ERROR);
BluetoothOppUtility.closeSendFileInfo(CORRECT_FORMAT_BUT_INVALID_FILE_URI);
} catch (Exception e) {
assertWithMessage("Exception should not happen.").fail();
}
}
}