Add a ContentDataSource contract test

PiperOrigin-RevId: 346954787
This commit is contained in:
ibaker 2020-12-11 09:34:24 +00:00 committed by Ian Baker
parent 05c928f96d
commit 73b9cee83a
5 changed files with 190 additions and 107 deletions

View File

@ -26,7 +26,7 @@
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
<provider
android:authorities="com.google.android.exoplayer2.core.test"
android:name="com.google.android.exoplayer2.upstream.ContentDataSourceTest$TestContentProvider"/>
android:name="com.google.android.exoplayer2.upstream.TestContentProvider"/>
</application>
<instrumentation

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2020 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.google.android.exoplayer2.upstream;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.testutil.DataSourceContractTest;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.common.collect.ImmutableList;
import org.junit.runner.RunWith;
/** {@link DataSource} contract tests for {@link ContentDataSource}. */
@RunWith(AndroidJUnit4.class)
public final class ContentDataSourceContractTest extends DataSourceContractTest {
private static final String DATA_PATH = "media/mp3/1024_incrementing_bytes.mp3";
@Override
protected DataSource createDataSource() {
return new ContentDataSource(ApplicationProvider.getApplicationContext());
}
@Override
protected ImmutableList<TestResource> getTestResources() throws Exception {
byte[] completeData =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), DATA_PATH);
return ImmutableList.of(
new TestResource.Builder()
.setName("simple (pipe=false)")
.setUri(TestContentProvider.buildUri(DATA_PATH, /* pipeMode= */ false))
.setExpectedBytes(completeData)
.build(),
new TestResource.Builder()
.setName("simple (pipe=true)")
.setUri(TestContentProvider.buildUri(DATA_PATH, /* pipeMode= */ true))
.setExpectedBytes(completeData)
.resolvesToUnknownLength()
.build());
}
@Override
protected Uri getNotFoundUri() {
return TestContentProvider.buildUri("not/a/real/path", /* pipeMode= */ false);
}
}

View File

@ -19,15 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertThrows;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
@ -35,7 +27,6 @@ import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.ContentDataSource.ContentDataSourceException;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import org.junit.Test;
@ -45,7 +36,6 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public final class ContentDataSourceTest {
private static final String AUTHORITY = "com.google.android.exoplayer2.core.test";
private static final String DATA_PATH = "media/mp3/1024_incrementing_bytes.mp3";
@Test
@ -141,98 +131,4 @@ public final class ContentDataSourceTest {
}
}
/**
* A {@link ContentProvider} for the test.
*/
public static final class TestContentProvider extends ContentProvider
implements ContentProvider.PipeDataWriter<Object> {
private static final String PARAM_PIPE_MODE = "pipe-mode";
public static Uri buildUri(String filePath, boolean pipeMode) {
Uri.Builder builder = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY)
.path(filePath);
if (pipeMode) {
builder.appendQueryParameter(TestContentProvider.PARAM_PIPE_MODE, "1");
}
return builder.build();
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(
Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
throw new UnsupportedOperationException();
}
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
if (uri.getPath() == null) {
return null;
}
try {
String fileName = getFileName(uri);
boolean pipeMode = uri.getQueryParameter(PARAM_PIPE_MODE) != null;
if (pipeMode) {
ParcelFileDescriptor fileDescriptor = openPipeHelper(uri, null, null, null, this);
return new AssetFileDescriptor(fileDescriptor, 0, C.LENGTH_UNSET);
} else {
return getContext().getAssets().openFd(fileName);
}
} catch (IOException e) {
FileNotFoundException exception = new FileNotFoundException(e.getMessage());
exception.initCause(e);
throw exception;
}
}
@Override
public String getType(Uri uri) {
throw new UnsupportedOperationException();
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException();
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override
public void writeDataToPipe(
ParcelFileDescriptor output,
Uri uri,
String mimeType,
@Nullable Bundle opts,
@Nullable Object args) {
try {
byte[] data = TestUtil.getByteArray(getContext(), getFileName(uri));
FileOutputStream outputStream = new FileOutputStream(output.getFileDescriptor());
outputStream.write(data);
outputStream.close();
} catch (IOException e) {
throw new RuntimeException("Error writing to pipe", e);
}
}
private static String getFileName(Uri uri) {
return uri.getPath().replaceFirst("/", "");
}
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright (C) 2020 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.google.android.exoplayer2.upstream;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/** A {@link ContentProvider} for tests of {@link ContentDataSource}. */
public final class TestContentProvider extends ContentProvider
implements ContentProvider.PipeDataWriter<Object> {
private static final String AUTHORITY = "com.google.android.exoplayer2.core.test";
private static final String PARAM_PIPE_MODE = "pipe-mode";
public static Uri buildUri(String filePath, boolean pipeMode) {
Uri.Builder builder =
new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY)
.path(filePath);
if (pipeMode) {
builder.appendQueryParameter(TestContentProvider.PARAM_PIPE_MODE, "1");
}
return builder.build();
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(
Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
throw new UnsupportedOperationException();
}
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
if (uri.getPath() == null) {
return null;
}
try {
String fileName = getFileName(uri);
boolean pipeMode = uri.getQueryParameter(PARAM_PIPE_MODE) != null;
if (pipeMode) {
ParcelFileDescriptor fileDescriptor =
openPipeHelper(
uri, /* mimeType= */ null, /* opts= */ null, /* args= */ null, /* func= */ this);
return new AssetFileDescriptor(
fileDescriptor, /* startOffset= */ 0, /* length= */ C.LENGTH_UNSET);
} else {
return getContext().getAssets().openFd(fileName);
}
} catch (IOException e) {
FileNotFoundException exception = new FileNotFoundException(e.getMessage());
exception.initCause(e);
throw exception;
}
}
@Override
public String getType(Uri uri) {
throw new UnsupportedOperationException();
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException();
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override
public void writeDataToPipe(
ParcelFileDescriptor output,
Uri uri,
String mimeType,
@Nullable Bundle opts,
@Nullable Object args) {
try {
byte[] data = TestUtil.getByteArray(getContext(), getFileName(uri));
FileOutputStream outputStream = new FileOutputStream(output.getFileDescriptor());
outputStream.write(data);
outputStream.close();
} catch (IOException e) {
throw new RuntimeException("Error writing to pipe", e);
}
}
private static String getFileName(Uri uri) {
return uri.getPath().replaceFirst("/", "");
}
}

View File

@ -55,7 +55,7 @@ public abstract class DataSourceContractTest {
@Rule public final AdditionalFailureInfo additionalFailureInfo = new AdditionalFailureInfo();
/** Creates and returns an instance of the {@link DataSource}. */
protected abstract DataSource createDataSource();
protected abstract DataSource createDataSource() throws Exception;
/**
* Returns {@link TestResource} instances.
@ -66,7 +66,7 @@ public abstract class DataSourceContractTest {
* <p>If multiple resources are returned, it's recommended to disambiguate them using {@link
* TestResource.Builder#setName(String)}.
*/
protected abstract ImmutableList<TestResource> getTestResources();
protected abstract ImmutableList<TestResource> getTestResources() throws Exception;
/**
* Returns a {@link Uri} that doesn't resolve.