Add a ContentDataSource contract test
PiperOrigin-RevId: 346954787
This commit is contained in:
parent
05c928f96d
commit
73b9cee83a
@ -26,7 +26,7 @@
|
|||||||
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
|
tools:ignore="MissingApplicationIcon,HardcodedDebugMode">
|
||||||
<provider
|
<provider
|
||||||
android:authorities="com.google.android.exoplayer2.core.test"
|
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>
|
</application>
|
||||||
|
|
||||||
<instrumentation
|
<instrumentation
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -19,15 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import static junit.framework.Assert.fail;
|
import static junit.framework.Assert.fail;
|
||||||
import static org.junit.Assert.assertThrows;
|
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.net.Uri;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
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 com.google.android.exoplayer2.upstream.ContentDataSource.ContentDataSourceException;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -45,7 +36,6 @@ import org.junit.runner.RunWith;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class ContentDataSourceTest {
|
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";
|
private static final String DATA_PATH = "media/mp3/1024_incrementing_bytes.mp3";
|
||||||
|
|
||||||
@Test
|
@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("/", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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("/", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -55,7 +55,7 @@ public abstract class DataSourceContractTest {
|
|||||||
@Rule public final AdditionalFailureInfo additionalFailureInfo = new AdditionalFailureInfo();
|
@Rule public final AdditionalFailureInfo additionalFailureInfo = new AdditionalFailureInfo();
|
||||||
|
|
||||||
/** Creates and returns an instance of the {@link DataSource}. */
|
/** Creates and returns an instance of the {@link DataSource}. */
|
||||||
protected abstract DataSource createDataSource();
|
protected abstract DataSource createDataSource() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link TestResource} instances.
|
* 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
|
* <p>If multiple resources are returned, it's recommended to disambiguate them using {@link
|
||||||
* TestResource.Builder#setName(String)}.
|
* TestResource.Builder#setName(String)}.
|
||||||
*/
|
*/
|
||||||
protected abstract ImmutableList<TestResource> getTestResources();
|
protected abstract ImmutableList<TestResource> getTestResources() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Uri} that doesn't resolve.
|
* Returns a {@link Uri} that doesn't resolve.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user