Start fixing nullness in testutil
PiperOrigin-RevId: 292340530
This commit is contained in:
parent
ff822ff9fd
commit
7c8a54c6d0
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.chunk;
|
package com.google.android.exoplayer2.source.chunk;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
|
import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
|
||||||
@ -54,7 +55,7 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
|
|||||||
DataSpec dataSpec,
|
DataSpec dataSpec,
|
||||||
Format trackFormat,
|
Format trackFormat,
|
||||||
int trackSelectionReason,
|
int trackSelectionReason,
|
||||||
Object trackSelectionData,
|
@Nullable Object trackSelectionData,
|
||||||
long startTimeUs,
|
long startTimeUs,
|
||||||
long endTimeUs,
|
long endTimeUs,
|
||||||
long chunkIndex,
|
long chunkIndex,
|
||||||
|
@ -821,7 +821,8 @@ public final class ExoPlayerTest {
|
|||||||
new FakeMediaSource(timeline, Builder.VIDEO_FORMAT, Builder.AUDIO_FORMAT);
|
new FakeMediaSource(timeline, Builder.VIDEO_FORMAT, Builder.AUDIO_FORMAT);
|
||||||
FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
|
FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
|
||||||
FakeRenderer audioRenderer = new FakeRenderer(Builder.AUDIO_FORMAT);
|
FakeRenderer audioRenderer = new FakeRenderer(Builder.AUDIO_FORMAT);
|
||||||
final FakeTrackSelector trackSelector = new FakeTrackSelector(/* reuse track selection */ true);
|
final FakeTrackSelector trackSelector =
|
||||||
|
new FakeTrackSelector(/* mayReuseTrackSelection= */ true);
|
||||||
ActionSchedule disableTrackAction =
|
ActionSchedule disableTrackAction =
|
||||||
new ActionSchedule.Builder("testReuseTrackSelection")
|
new ActionSchedule.Builder("testReuseTrackSelection")
|
||||||
.pause()
|
.pause()
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.util.HandlerWrapper;
|
import com.google.android.exoplayer2.util.HandlerWrapper;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link FakeClock} extension which automatically advances time whenever an empty message is
|
* {@link FakeClock} extension which automatically advances time whenever an empty message is
|
||||||
@ -25,7 +26,7 @@ import com.google.android.exoplayer2.util.HandlerWrapper;
|
|||||||
*/
|
*/
|
||||||
public final class AutoAdvancingFakeClock extends FakeClock {
|
public final class AutoAdvancingFakeClock extends FakeClock {
|
||||||
|
|
||||||
private HandlerWrapper autoAdvancingHandler;
|
private @MonotonicNonNull HandlerWrapper autoAdvancingHandler;
|
||||||
|
|
||||||
public AutoAdvancingFakeClock() {
|
public AutoAdvancingFakeClock() {
|
||||||
super(/* initialTimeMs= */ 0);
|
super(/* initialTimeMs= */ 0);
|
||||||
|
@ -21,6 +21,7 @@ import android.content.Context;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.audio.AudioSink;
|
import com.google.android.exoplayer2.audio.AudioSink;
|
||||||
import com.google.android.exoplayer2.audio.ForwardingAudioSink;
|
import com.google.android.exoplayer2.audio.ForwardingAudioSink;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -122,7 +123,7 @@ public final class CapturingAudioSink extends ForwardingAudioSink implements Dum
|
|||||||
if (WRITE_DUMP) {
|
if (WRITE_DUMP) {
|
||||||
File directory = context.getExternalFilesDir(null);
|
File directory = context.getExternalFilesDir(null);
|
||||||
File file = new File(directory, dumpFile);
|
File file = new File(directory, dumpFile);
|
||||||
file.getParentFile().mkdirs();
|
Assertions.checkStateNotNull(file.getParentFile()).mkdirs();
|
||||||
PrintWriter out = new PrintWriter(file);
|
PrintWriter out = new PrintWriter(file);
|
||||||
out.print(actual);
|
out.print(actual);
|
||||||
out.close();
|
out.close();
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -44,7 +45,7 @@ public final class Dumper {
|
|||||||
sb = new StringBuilder();
|
sb = new StringBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dumper add(String field, Object value) {
|
public Dumper add(String field, @Nullable Object value) {
|
||||||
return addString(field + " = " + value + '\n');
|
return addString(field + " = " + value + '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,8 +54,13 @@ public final class Dumper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dumper add(String field, byte[] value) {
|
public Dumper add(String field, @Nullable byte[] value) {
|
||||||
String string = String.format(Locale.US, "%s = length %d, hash %X\n", field, value.length,
|
String string =
|
||||||
|
String.format(
|
||||||
|
Locale.US,
|
||||||
|
"%s = length %d, hash %X\n",
|
||||||
|
field,
|
||||||
|
value == null ? 0 : value.length,
|
||||||
Arrays.hashCode(value));
|
Arrays.hashCode(value));
|
||||||
return addString(string);
|
return addString(string);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ public final class ExtractorAsserts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the SeekMap is seekable, test seeking in the stream.
|
// If the SeekMap is seekable, test seeking in the stream.
|
||||||
SeekMap seekMap = extractorOutput.seekMap;
|
SeekMap seekMap = Assertions.checkNotNull(extractorOutput.seekMap);
|
||||||
if (seekMap.isSeekable()) {
|
if (seekMap.isSeekable()) {
|
||||||
long durationUs = seekMap.getDurationUs();
|
long durationUs = seekMap.getDurationUs();
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
@ -361,7 +361,7 @@ public final class ExtractorAsserts {
|
|||||||
int i = fileName.lastIndexOf('/');
|
int i = fileName.lastIndexOf('/');
|
||||||
String path = i >= 0 ? fileName.substring(0, i) : "";
|
String path = i >= 0 ? fileName.substring(0, i) : "";
|
||||||
String file = i >= 0 ? fileName.substring(i + 1) : fileName;
|
String file = i >= 0 ? fileName.substring(i + 1) : fileName;
|
||||||
return Arrays.asList(context.getResources().getAssets().list(path)).contains(file);
|
String[] assets = context.getResources().getAssets().list(path);
|
||||||
|
return assets != null && Arrays.asList(assets).contains(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator;
|
|||||||
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
|
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +93,7 @@ public final class FakeAdaptiveDataSet extends FakeDataSet {
|
|||||||
checkInBounds();
|
checkInBounds();
|
||||||
String uri = dataSet.getUri(trackGroupIndex);
|
String uri = dataSet.getUri(trackGroupIndex);
|
||||||
int chunkIndex = (int) getCurrentIndex();
|
int chunkIndex = (int) getCurrentIndex();
|
||||||
Segment fakeDataChunk = dataSet.getData(uri).getSegments().get(chunkIndex);
|
Segment fakeDataChunk = Util.castNonNull(dataSet.getData(uri)).getSegments().get(chunkIndex);
|
||||||
return new DataSpec(
|
return new DataSpec(
|
||||||
Uri.parse(uri), fakeDataChunk.byteOffset, fakeDataChunk.length, /* key= */ null);
|
Uri.parse(uri), fakeDataChunk.byteOffset, fakeDataChunk.length, /* key= */ null);
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,12 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake {@link MediaPeriod} that provides tracks from the given {@link TrackGroupArray}. Selecting a
|
* Fake {@link MediaPeriod} that provides tracks from the given {@link TrackGroupArray}. Selecting a
|
||||||
@ -44,7 +47,7 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||||||
@Nullable private final TransferListener transferListener;
|
@Nullable private final TransferListener transferListener;
|
||||||
private final long durationUs;
|
private final long durationUs;
|
||||||
|
|
||||||
private Callback callback;
|
@MonotonicNonNull private Callback callback;
|
||||||
private ChunkSampleStream<FakeChunkSource>[] sampleStreams;
|
private ChunkSampleStream<FakeChunkSource>[] sampleStreams;
|
||||||
private SequenceableLoader sequenceableLoader;
|
private SequenceableLoader sequenceableLoader;
|
||||||
|
|
||||||
@ -81,9 +84,9 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public long selectTracks(
|
public long selectTracks(
|
||||||
TrackSelection[] selections,
|
@NullableType TrackSelection[] selections,
|
||||||
boolean[] mayRetainStreamFlags,
|
boolean[] mayRetainStreamFlags,
|
||||||
SampleStream[] streams,
|
@NullableType SampleStream[] streams,
|
||||||
boolean[] streamResetFlags,
|
boolean[] streamResetFlags,
|
||||||
long positionUs) {
|
long positionUs) {
|
||||||
long returnPositionUs = super.selectTracks(selections, mayRetainStreamFlags, streams,
|
long returnPositionUs = super.selectTracks(selections, mayRetainStreamFlags, streams,
|
||||||
@ -94,7 +97,8 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||||||
validStreams.add((ChunkSampleStream<FakeChunkSource>) stream);
|
validStreams.add((ChunkSampleStream<FakeChunkSource>) stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sampleStreams = validStreams.toArray(newSampleStreamArray(validStreams.size()));
|
sampleStreams = newSampleStreamArray(validStreams.size());
|
||||||
|
validStreams.toArray(sampleStreams);
|
||||||
this.sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
this.sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
||||||
return returnPositionUs;
|
return returnPositionUs;
|
||||||
}
|
}
|
||||||
@ -162,7 +166,7 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContinueLoadingRequested(ChunkSampleStream<FakeChunkSource> source) {
|
public void onContinueLoadingRequested(ChunkSampleStream<FakeChunkSource> source) {
|
||||||
callback.onContinueLoadingRequested(this);
|
Assertions.checkStateNotNull(callback).onContinueLoadingRequested(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We won't assign the array to a variable that erases the generic type, and then write into it.
|
// We won't assign the array to a variable that erases the generic type, and then write into it.
|
||||||
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
import android.os.Handler.Callback;
|
import android.os.Handler.Callback;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.util.Clock;
|
import com.google.android.exoplayer2.util.Clock;
|
||||||
import com.google.android.exoplayer2.util.HandlerWrapper;
|
import com.google.android.exoplayer2.util.HandlerWrapper;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -90,7 +91,7 @@ public class FakeClock implements Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerWrapper createHandler(Looper looper, Callback callback) {
|
public HandlerWrapper createHandler(Looper looper, @Nullable Callback callback) {
|
||||||
return new ClockHandler(looper, callback);
|
return new ClockHandler(looper, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ public class FakeClock implements Clock {
|
|||||||
|
|
||||||
private final long postTime;
|
private final long postTime;
|
||||||
private final HandlerWrapper handler;
|
private final HandlerWrapper handler;
|
||||||
private final Runnable runnable;
|
@Nullable private final Runnable runnable;
|
||||||
private final int message;
|
private final int message;
|
||||||
|
|
||||||
public HandlerMessageData(long postTime, HandlerWrapper handler, Runnable runnable) {
|
public HandlerMessageData(long postTime, HandlerWrapper handler, Runnable runnable) {
|
||||||
@ -155,7 +156,7 @@ public class FakeClock implements Clock {
|
|||||||
|
|
||||||
private final android.os.Handler handler;
|
private final android.os.Handler handler;
|
||||||
|
|
||||||
public ClockHandler(Looper looper, Callback callback) {
|
public ClockHandler(Looper looper, @Nullable Callback callback) {
|
||||||
handler = new android.os.Handler(looper, callback);
|
handler = new android.os.Handler(looper, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +171,7 @@ public class FakeClock implements Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message obtainMessage(int what, Object obj) {
|
public Message obtainMessage(int what, @Nullable Object obj) {
|
||||||
return handler.obtainMessage(what, obj);
|
return handler.obtainMessage(what, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +181,7 @@ public class FakeClock implements Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message obtainMessage(int what, int arg1, int arg2, Object obj) {
|
public Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
|
||||||
return handler.obtainMessage(what, arg1, arg2, obj);
|
return handler.obtainMessage(what, arg1, arg2, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +201,7 @@ public class FakeClock implements Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeCallbacksAndMessages(Object token) {
|
public void removeCallbacksAndMessages(@Nullable Object token) {
|
||||||
handler.removeCallbacksAndMessages(token);
|
handler.removeCallbacksAndMessages(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,24 +89,28 @@ public class FakeDataSet {
|
|||||||
public boolean exceptionCleared;
|
public boolean exceptionCleared;
|
||||||
public int bytesRead;
|
public int bytesRead;
|
||||||
|
|
||||||
private Segment(byte[] data, Segment previousSegment) {
|
private Segment(byte[] data, @Nullable Segment previousSegment) {
|
||||||
this(data, data.length, null, null, previousSegment);
|
this(data, data.length, null, null, previousSegment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Segment(int length, Segment previousSegment) {
|
private Segment(int length, @Nullable Segment previousSegment) {
|
||||||
this(null, length, null, null, previousSegment);
|
this(null, length, null, null, previousSegment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Segment(IOException exception, Segment previousSegment) {
|
private Segment(IOException exception, @Nullable Segment previousSegment) {
|
||||||
this(null, 0, exception, null, previousSegment);
|
this(null, 0, exception, null, previousSegment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Segment(Runnable action, Segment previousSegment) {
|
private Segment(Runnable action, @Nullable Segment previousSegment) {
|
||||||
this(null, 0, null, action, previousSegment);
|
this(null, 0, null, action, previousSegment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Segment(@Nullable byte[] data, int length, @Nullable IOException exception,
|
private Segment(
|
||||||
@Nullable Runnable action, Segment previousSegment) {
|
@Nullable byte[] data,
|
||||||
|
int length,
|
||||||
|
@Nullable IOException exception,
|
||||||
|
@Nullable Runnable action,
|
||||||
|
@Nullable Segment previousSegment) {
|
||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
@ -125,16 +129,17 @@ public class FakeDataSet {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Uri of the data or null if this is the default FakeData. */
|
|
||||||
public final Uri uri;
|
|
||||||
private final ArrayList<Segment> segments;
|
|
||||||
private final FakeDataSet dataSet;
|
private final FakeDataSet dataSet;
|
||||||
|
/** Uri of the data or null if this is the default FakeData. */
|
||||||
|
@Nullable public final Uri uri;
|
||||||
|
|
||||||
|
private final ArrayList<Segment> segments;
|
||||||
private boolean simulateUnknownLength;
|
private boolean simulateUnknownLength;
|
||||||
|
|
||||||
private FakeData(FakeDataSet dataSet, Uri uri) {
|
private FakeData(FakeDataSet dataSet, @Nullable Uri uri) {
|
||||||
|
this.dataSet = dataSet;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.segments = new ArrayList<>();
|
this.segments = new ArrayList<>();
|
||||||
this.dataSet = dataSet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the {@link FakeDataSet} this FakeData belongs to. */
|
/** Returns the {@link FakeDataSet} this FakeData belongs to. */
|
||||||
@ -157,7 +162,7 @@ public class FakeDataSet {
|
|||||||
* Appends to the underlying data.
|
* Appends to the underlying data.
|
||||||
*/
|
*/
|
||||||
public FakeData appendReadData(byte[] data) {
|
public FakeData appendReadData(byte[] data) {
|
||||||
Assertions.checkState(data != null && data.length > 0);
|
Assertions.checkState(data.length > 0);
|
||||||
segments.add(new Segment(data, getLastSegment()));
|
segments.add(new Segment(data, getLastSegment()));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -213,6 +218,7 @@ public class FakeDataSet {
|
|||||||
return simulateUnknownLength;
|
return simulateUnknownLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private Segment getLastSegment() {
|
private Segment getLastSegment() {
|
||||||
int count = segments.size();
|
int count = segments.size();
|
||||||
return count > 0 ? segments.get(count - 1) : null;
|
return count > 0 ? segments.get(count - 1) : null;
|
||||||
@ -221,7 +227,7 @@ public class FakeDataSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final HashMap<Uri, FakeData> dataMap;
|
private final HashMap<Uri, FakeData> dataMap;
|
||||||
private FakeData defaultData;
|
@Nullable private FakeData defaultData;
|
||||||
|
|
||||||
public FakeDataSet() {
|
public FakeDataSet() {
|
||||||
dataMap = new HashMap<>();
|
dataMap = new HashMap<>();
|
||||||
@ -266,13 +272,15 @@ public class FakeDataSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */
|
/** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */
|
||||||
|
@Nullable
|
||||||
public FakeData getData(String uri) {
|
public FakeData getData(String uri) {
|
||||||
return getData(Uri.parse(uri));
|
return getData(Uri.parse(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */
|
/** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */
|
||||||
|
@Nullable
|
||||||
public FakeData getData(Uri uri) {
|
public FakeData getData(Uri uri) {
|
||||||
FakeData data = dataMap.get(uri);
|
@Nullable FakeData data = dataMap.get(uri);
|
||||||
return data != null ? data : defaultData;
|
return data != null ? data : defaultData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData;
|
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
|
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
|
||||||
@ -24,8 +25,10 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSourceException;
|
import com.google.android.exoplayer2.upstream.DataSourceException;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fake {@link DataSource} capable of simulating various scenarios. It uses a {@link FakeDataSet}
|
* A fake {@link DataSource} capable of simulating various scenarios. It uses a {@link FakeDataSet}
|
||||||
@ -38,7 +41,7 @@ public class FakeDataSource extends BaseDataSource {
|
|||||||
*/
|
*/
|
||||||
public static class Factory implements DataSource.Factory {
|
public static class Factory implements DataSource.Factory {
|
||||||
|
|
||||||
protected FakeDataSet fakeDataSet;
|
protected @MonotonicNonNull FakeDataSet fakeDataSet;
|
||||||
protected boolean isNetwork;
|
protected boolean isNetwork;
|
||||||
|
|
||||||
public final Factory setFakeDataSet(FakeDataSet fakeDataSet) {
|
public final Factory setFakeDataSet(FakeDataSet fakeDataSet) {
|
||||||
@ -53,17 +56,17 @@ public class FakeDataSource extends BaseDataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FakeDataSource createDataSource() {
|
public FakeDataSource createDataSource() {
|
||||||
return new FakeDataSource(fakeDataSet, isNetwork);
|
return new FakeDataSource(Assertions.checkStateNotNull(fakeDataSet), isNetwork);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FakeDataSet fakeDataSet;
|
private final FakeDataSet fakeDataSet;
|
||||||
private final ArrayList<DataSpec> openedDataSpecs;
|
private final ArrayList<DataSpec> openedDataSpecs;
|
||||||
|
|
||||||
private Uri uri;
|
@Nullable private Uri uri;
|
||||||
private boolean openCalled;
|
private boolean openCalled;
|
||||||
private boolean sourceOpened;
|
private boolean sourceOpened;
|
||||||
private FakeData fakeData;
|
@Nullable private FakeData fakeData;
|
||||||
private int currentSegmentIndex;
|
private int currentSegmentIndex;
|
||||||
private long bytesRemaining;
|
private long bytesRemaining;
|
||||||
|
|
||||||
@ -96,10 +99,11 @@ public class FakeDataSource extends BaseDataSource {
|
|||||||
openedDataSpecs.add(dataSpec);
|
openedDataSpecs.add(dataSpec);
|
||||||
|
|
||||||
transferInitializing(dataSpec);
|
transferInitializing(dataSpec);
|
||||||
fakeData = fakeDataSet.getData(uri.toString());
|
FakeData fakeData = fakeDataSet.getData(dataSpec.uri.toString());
|
||||||
if (fakeData == null) {
|
if (fakeData == null) {
|
||||||
throw new IOException("Data not found: " + dataSpec.uri);
|
throw new IOException("Data not found: " + dataSpec.uri);
|
||||||
}
|
}
|
||||||
|
this.fakeData = fakeData;
|
||||||
|
|
||||||
long totalLength = 0;
|
long totalLength = 0;
|
||||||
for (Segment segment : fakeData.getSegments()) {
|
for (Segment segment : fakeData.getSegments()) {
|
||||||
@ -145,6 +149,7 @@ public class FakeDataSource extends BaseDataSource {
|
|||||||
public final int read(byte[] buffer, int offset, int readLength) throws IOException {
|
public final int read(byte[] buffer, int offset, int readLength) throws IOException {
|
||||||
Assertions.checkState(sourceOpened);
|
Assertions.checkState(sourceOpened);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
FakeData fakeData = Util.castNonNull(this.fakeData);
|
||||||
if (currentSegmentIndex == fakeData.getSegments().size() || bytesRemaining == 0) {
|
if (currentSegmentIndex == fakeData.getSegments().size() || bytesRemaining == 0) {
|
||||||
return C.RESULT_END_OF_INPUT;
|
return C.RESULT_END_OF_INPUT;
|
||||||
}
|
}
|
||||||
@ -152,13 +157,13 @@ public class FakeDataSource extends BaseDataSource {
|
|||||||
if (current.isErrorSegment()) {
|
if (current.isErrorSegment()) {
|
||||||
if (!current.exceptionCleared) {
|
if (!current.exceptionCleared) {
|
||||||
current.exceptionThrown = true;
|
current.exceptionThrown = true;
|
||||||
throw (IOException) current.exception.fillInStackTrace();
|
throw (IOException) Util.castNonNull(current.exception).fillInStackTrace();
|
||||||
} else {
|
} else {
|
||||||
currentSegmentIndex++;
|
currentSegmentIndex++;
|
||||||
}
|
}
|
||||||
} else if (current.isActionSegment()) {
|
} else if (current.isActionSegment()) {
|
||||||
currentSegmentIndex++;
|
currentSegmentIndex++;
|
||||||
current.action.run();
|
Util.castNonNull(current.action).run();
|
||||||
} else {
|
} else {
|
||||||
// Read at most bytesRemaining.
|
// Read at most bytesRemaining.
|
||||||
readLength = (int) Math.min(readLength, bytesRemaining);
|
readLength = (int) Math.min(readLength, bytesRemaining);
|
||||||
@ -181,13 +186,14 @@ public class FakeDataSource extends BaseDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public final Uri getUri() {
|
public final Uri getUri() {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void close() throws IOException {
|
public final void close() {
|
||||||
Assertions.checkState(openCalled);
|
Assertions.checkState(openCalled);
|
||||||
openCalled = false;
|
openCalled = false;
|
||||||
uri = null;
|
uri = null;
|
||||||
|
@ -20,12 +20,15 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fake {@link ExtractorOutput}.
|
* A fake {@link ExtractorOutput}.
|
||||||
@ -45,7 +48,7 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
|||||||
|
|
||||||
public int numberOfTracks;
|
public int numberOfTracks;
|
||||||
public boolean tracksEnded;
|
public boolean tracksEnded;
|
||||||
public SeekMap seekMap;
|
public @MonotonicNonNull SeekMap seekMap;
|
||||||
|
|
||||||
public FakeExtractorOutput() {
|
public FakeExtractorOutput() {
|
||||||
trackOutputs = new SparseArray<>();
|
trackOutputs = new SparseArray<>();
|
||||||
@ -53,7 +56,7 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FakeTrackOutput track(int id, int type) {
|
public FakeTrackOutput track(int id, int type) {
|
||||||
FakeTrackOutput output = trackOutputs.get(id);
|
@Nullable FakeTrackOutput output = trackOutputs.get(id);
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
assertThat(tracksEnded).isFalse();
|
assertThat(tracksEnded).isFalse();
|
||||||
numberOfTracks++;
|
numberOfTracks++;
|
||||||
@ -99,10 +102,11 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
|||||||
assertThat(seekMap).isNull();
|
assertThat(seekMap).isNull();
|
||||||
} else {
|
} else {
|
||||||
// TODO: Bulk up this check if possible.
|
// TODO: Bulk up this check if possible.
|
||||||
assertThat(seekMap).isNotNull();
|
SeekMap expectedSeekMap = Assertions.checkNotNull(expected.seekMap);
|
||||||
assertThat(seekMap.getClass()).isEqualTo(expected.seekMap.getClass());
|
SeekMap seekMap = Assertions.checkNotNull(this.seekMap);
|
||||||
assertThat(seekMap.isSeekable()).isEqualTo(expected.seekMap.isSeekable());
|
assertThat(seekMap.getClass()).isEqualTo(expectedSeekMap.getClass());
|
||||||
assertThat(seekMap.getSeekPoints(0)).isEqualTo(expected.seekMap.getSeekPoints(0));
|
assertThat(seekMap.isSeekable()).isEqualTo(expectedSeekMap.isSeekable());
|
||||||
|
assertThat(seekMap.getSeekPoints(0)).isEqualTo(expectedSeekMap.getSeekPoints(0));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < numberOfTracks; i++) {
|
for (int i = 0; i < numberOfTracks; i++) {
|
||||||
assertThat(trackOutputs.keyAt(i)).isEqualTo(expected.trackOutputs.keyAt(i));
|
assertThat(trackOutputs.keyAt(i)).isEqualTo(expected.trackOutputs.keyAt(i));
|
||||||
@ -125,7 +129,7 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
|||||||
if (WRITE_DUMP) {
|
if (WRITE_DUMP) {
|
||||||
File file = new File(System.getProperty("user.dir"), "src/test/assets");
|
File file = new File(System.getProperty("user.dir"), "src/test/assets");
|
||||||
file = new File(file, dumpFile);
|
file = new File(file, dumpFile);
|
||||||
file.getParentFile().mkdirs();
|
Assertions.checkStateNotNull(file.getParentFile()).mkdirs();
|
||||||
PrintWriter out = new PrintWriter(file);
|
PrintWriter out = new PrintWriter(file);
|
||||||
out.print(actual);
|
out.print(actual);
|
||||||
out.close();
|
out.close();
|
||||||
|
@ -22,7 +22,6 @@ import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/** Fake {@link MediaChunk}. */
|
/** Fake {@link MediaChunk}. */
|
||||||
public final class FakeMediaChunk extends MediaChunk {
|
public final class FakeMediaChunk extends MediaChunk {
|
||||||
@ -51,7 +50,7 @@ public final class FakeMediaChunk extends MediaChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() throws IOException, InterruptedException {
|
public void load() {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake {@link MediaPeriod} that provides tracks from the given {@link TrackGroupArray}. Selecting
|
* Fake {@link MediaPeriod} that provides tracks from the given {@link TrackGroupArray}. Selecting
|
||||||
@ -149,8 +150,12 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
|
public long selectTracks(
|
||||||
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
|
@NullableType TrackSelection[] selections,
|
||||||
|
boolean[] mayRetainStreamFlags,
|
||||||
|
@NullableType SampleStream[] streams,
|
||||||
|
boolean[] streamResetFlags,
|
||||||
|
long positionUs) {
|
||||||
assertThat(prepared).isTrue();
|
assertThat(prepared).isTrue();
|
||||||
sampleStreams.clear();
|
sampleStreams.clear();
|
||||||
int rendererCount = selections.length;
|
int rendererCount = selections.length;
|
||||||
|
@ -84,7 +84,7 @@ public class FakeRenderer extends BaseRenderer {
|
|||||||
if (result == C.RESULT_FORMAT_READ) {
|
if (result == C.RESULT_FORMAT_READ) {
|
||||||
formatReadCount++;
|
formatReadCount++;
|
||||||
assertThat(expectedFormats).contains(formatHolder.format);
|
assertThat(expectedFormats).contains(formatHolder.format);
|
||||||
onFormatChanged(formatHolder.format);
|
onFormatChanged(Assertions.checkNotNull(formatHolder.format));
|
||||||
} else if (result == C.RESULT_BUFFER_READ) {
|
} else if (result == C.RESULT_BUFFER_READ) {
|
||||||
if (buffer.isEndOfStream()) {
|
if (buffer.isEndOfStream()) {
|
||||||
isEnded = true;
|
isEnded = true;
|
||||||
|
@ -24,9 +24,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/** Fake {@link Timeline} which can be setup to return custom {@link TimelineWindowDefinition}s. */
|
||||||
* Fake {@link Timeline} which can be setup to return custom {@link TimelineWindowDefinition}s.
|
|
||||||
*/
|
|
||||||
public final class FakeTimeline extends Timeline {
|
public final class FakeTimeline extends Timeline {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
@ -29,6 +30,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fake {@link TrackOutput}.
|
* A fake {@link TrackOutput}.
|
||||||
@ -39,10 +42,10 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
private final ArrayList<Integer> sampleFlags;
|
private final ArrayList<Integer> sampleFlags;
|
||||||
private final ArrayList<Integer> sampleStartOffsets;
|
private final ArrayList<Integer> sampleStartOffsets;
|
||||||
private final ArrayList<Integer> sampleEndOffsets;
|
private final ArrayList<Integer> sampleEndOffsets;
|
||||||
private final ArrayList<CryptoData> cryptoDatas;
|
private final ArrayList<@NullableType CryptoData> cryptoDatas;
|
||||||
|
|
||||||
private byte[] sampleData;
|
private byte[] sampleData;
|
||||||
public Format format;
|
public @MonotonicNonNull Format format;
|
||||||
|
|
||||||
public FakeTrackOutput() {
|
public FakeTrackOutput() {
|
||||||
sampleData = Util.EMPTY_BYTE_ARRAY;
|
sampleData = Util.EMPTY_BYTE_ARRAY;
|
||||||
@ -64,6 +67,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void format(Format format) {
|
public void format(Format format) {
|
||||||
|
// TODO: Capture and assert all formats (interleaved with the samples).
|
||||||
this.format = format;
|
this.format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,8 +95,12 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
|
public void sampleMetadata(
|
||||||
CryptoData cryptoData) {
|
long timeUs,
|
||||||
|
@C.BufferFlags int flags,
|
||||||
|
int size,
|
||||||
|
int offset,
|
||||||
|
@Nullable CryptoData cryptoData) {
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
throw new IllegalStateException("TrackOutput must receive format before sampleMetadata");
|
throw new IllegalStateException("TrackOutput must receive format before sampleMetadata");
|
||||||
}
|
}
|
||||||
@ -110,7 +118,8 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
assertThat(sampleTimesUs).hasSize(count);
|
assertThat(sampleTimesUs).hasSize(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertSample(int index, byte[] data, long timeUs, int flags, CryptoData cryptoData) {
|
public void assertSample(
|
||||||
|
int index, byte[] data, long timeUs, int flags, @Nullable CryptoData cryptoData) {
|
||||||
byte[] actualData = getSampleData(index);
|
byte[] actualData = getSampleData(index);
|
||||||
assertThat(actualData).isEqualTo(data);
|
assertThat(actualData).isEqualTo(data);
|
||||||
assertThat(sampleTimesUs.get(index)).isEqualTo(timeUs);
|
assertThat(sampleTimesUs.get(index)).isEqualTo(timeUs);
|
||||||
@ -131,6 +140,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
return sampleFlags.get(index);
|
return sampleFlags.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public CryptoData getSampleCryptoData(int index) {
|
public CryptoData getSampleCryptoData(int index) {
|
||||||
return cryptoDatas.get(index);
|
return cryptoDatas.get(index);
|
||||||
}
|
}
|
||||||
@ -162,6 +172,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dump(Dumper dumper) {
|
public void dump(Dumper dumper) {
|
||||||
|
if (format != null) {
|
||||||
dumper
|
dumper
|
||||||
.startBlock("format")
|
.startBlock("format")
|
||||||
.add("bitrate", format.bitrate)
|
.add("bitrate", format.bitrate)
|
||||||
@ -190,6 +201,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
dumper.add("data", format.initializationData.get(i));
|
dumper.add("data", format.initializationData.get(i));
|
||||||
}
|
}
|
||||||
dumper.endBlock().endBlock();
|
dumper.endBlock().endBlock();
|
||||||
|
}
|
||||||
|
|
||||||
dumper.add("total output bytes", sampleData.length);
|
dumper.add("total output bytes", sampleData.length);
|
||||||
dumper.add("sample count", sampleTimesUs.size());
|
dumper.add("sample count", sampleTimesUs.size());
|
||||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
@ -109,6 +110,7 @@ public final class FakeTrackSelection implements TrackSelection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public Object getSelectionData() {
|
public Object getSelectionData() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport;
|
||||||
|
import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
@ -23,6 +25,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|||||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/** A fake {@link MappingTrackSelector} that returns {@link FakeTrackSelection}s. */
|
/** A fake {@link MappingTrackSelector} that returns {@link FakeTrackSelection}s. */
|
||||||
public class FakeTrackSelector extends DefaultTrackSelector {
|
public class FakeTrackSelector extends DefaultTrackSelector {
|
||||||
@ -30,7 +33,7 @@ public class FakeTrackSelector extends DefaultTrackSelector {
|
|||||||
private final FakeTrackSelectionFactory fakeTrackSelectionFactory;
|
private final FakeTrackSelectionFactory fakeTrackSelectionFactory;
|
||||||
|
|
||||||
public FakeTrackSelector() {
|
public FakeTrackSelector() {
|
||||||
this(false);
|
this(/* mayReuseTrackSelection= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,13 +51,14 @@ public class FakeTrackSelector extends DefaultTrackSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TrackSelection.Definition[] selectAllTracks(
|
protected TrackSelection.@NullableType Definition[] selectAllTracks(
|
||||||
MappedTrackInfo mappedTrackInfo,
|
MappedTrackInfo mappedTrackInfo,
|
||||||
int[][][] rendererFormatSupports,
|
@Capabilities int[][][] rendererFormatSupports,
|
||||||
int[] rendererMixedMimeTypeAdaptationSupports,
|
@AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupports,
|
||||||
Parameters params) {
|
Parameters params) {
|
||||||
int rendererCount = mappedTrackInfo.getRendererCount();
|
int rendererCount = mappedTrackInfo.getRendererCount();
|
||||||
TrackSelection.Definition[] definitions = new TrackSelection.Definition[rendererCount];
|
TrackSelection.@NullableType Definition[] definitions =
|
||||||
|
new TrackSelection.Definition[rendererCount];
|
||||||
for (int i = 0; i < rendererCount; i++) {
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
|
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
|
||||||
boolean hasTracks = trackGroupArray.length > 0;
|
boolean hasTracks = trackGroupArray.length > 0;
|
||||||
@ -80,7 +84,7 @@ public class FakeTrackSelector extends DefaultTrackSelector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackSelection[] createTrackSelections(
|
public TrackSelection[] createTrackSelections(
|
||||||
TrackSelection.Definition[] definitions, BandwidthMeter bandwidthMeter) {
|
@NullableType TrackSelection.Definition[] definitions, BandwidthMeter bandwidthMeter) {
|
||||||
TrackSelection[] selections = new TrackSelection[definitions.length];
|
TrackSelection[] selections = new TrackSelection[definitions.length];
|
||||||
for (int i = 0; i < definitions.length; i++) {
|
for (int i = 0; i < definitions.length; i++) {
|
||||||
TrackSelection.Definition definition = definitions[i];
|
TrackSelection.Definition definition = definitions[i];
|
||||||
|
@ -33,9 +33,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
/**
|
/** A host activity for performing playback tests. */
|
||||||
* A host activity for performing playback tests.
|
|
||||||
*/
|
|
||||||
public final class HostActivity extends Activity implements SurfaceHolder.Callback {
|
public final class HostActivity extends Activity implements SurfaceHolder.Callback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.BasePlayer;
|
import com.google.android.exoplayer2.BasePlayer;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
@ -250,7 +251,7 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
|
public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +261,7 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSeekParameters(SeekParameters seekParameters) {
|
public void setSeekParameters(@Nullable SeekParameters seekParameters) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,13 +18,16 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.offline.Download;
|
import com.google.android.exoplayer2.offline.Download;
|
||||||
import com.google.android.exoplayer2.offline.Download.State;
|
import com.google.android.exoplayer2.offline.Download.State;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/** A {@link DownloadManager.Listener} for testing. */
|
/** A {@link DownloadManager.Listener} for testing. */
|
||||||
public final class TestDownloadManagerListener implements DownloadManager.Listener {
|
public final class TestDownloadManagerListener implements DownloadManager.Listener {
|
||||||
@ -39,7 +42,7 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
|||||||
private final CountDownLatch initializedCondition;
|
private final CountDownLatch initializedCondition;
|
||||||
private final int timeoutMs;
|
private final int timeoutMs;
|
||||||
|
|
||||||
private CountDownLatch downloadFinishedCondition;
|
private @MonotonicNonNull CountDownLatch downloadFinishedCondition;
|
||||||
@Download.FailureReason private int failureReason;
|
@Download.FailureReason private int failureReason;
|
||||||
|
|
||||||
public TestDownloadManagerListener(
|
public TestDownloadManagerListener(
|
||||||
@ -57,6 +60,7 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
|||||||
downloadManager.addListener(this);
|
downloadManager.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public Integer pollStateChange(String taskId, long timeoutMs) throws InterruptedException {
|
public Integer pollStateChange(String taskId, long timeoutMs) throws InterruptedException {
|
||||||
return getStateQueue(taskId).poll(timeoutMs, TimeUnit.MILLISECONDS);
|
return getStateQueue(taskId).poll(timeoutMs, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
@ -112,7 +116,7 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
|||||||
dummyMainThread.runOnMainThread(
|
dummyMainThread.runOnMainThread(
|
||||||
() -> {
|
() -> {
|
||||||
if (downloadManager.isIdle()) {
|
if (downloadManager.isIdle()) {
|
||||||
downloadFinishedCondition.countDown();
|
Util.castNonNull(downloadFinishedCondition).countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertThat(downloadFinishedCondition.await(timeoutMs, TimeUnit.MILLISECONDS)).isTrue();
|
assertThat(downloadFinishedCondition.await(timeoutMs, TimeUnit.MILLISECONDS)).isTrue();
|
||||||
@ -120,10 +124,12 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
|||||||
|
|
||||||
private ArrayBlockingQueue<Integer> getStateQueue(String taskId) {
|
private ArrayBlockingQueue<Integer> getStateQueue(String taskId) {
|
||||||
synchronized (downloadStates) {
|
synchronized (downloadStates) {
|
||||||
if (!downloadStates.containsKey(taskId)) {
|
@Nullable ArrayBlockingQueue<Integer> stateQueue = downloadStates.get(taskId);
|
||||||
downloadStates.put(taskId, new ArrayBlockingQueue<>(10));
|
if (stateQueue == null) {
|
||||||
|
stateQueue = new ArrayBlockingQueue<>(10);
|
||||||
|
downloadStates.put(taskId, stateQueue);
|
||||||
}
|
}
|
||||||
return downloadStates.get(taskId);
|
return stateQueue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +143,11 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
|||||||
|
|
||||||
private void assertStateInternal(String taskId, int expectedState, int timeoutMs) {
|
private void assertStateInternal(String taskId, int expectedState, int timeoutMs) {
|
||||||
while (true) {
|
while (true) {
|
||||||
Integer state = null;
|
@Nullable Integer state = null;
|
||||||
try {
|
try {
|
||||||
state = pollStateChange(taskId, timeoutMs);
|
state = pollStateChange(taskId, timeoutMs);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
fail(e.getMessage());
|
fail("Interrupted: " + e.getMessage());
|
||||||
}
|
}
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
if (expectedState == state) {
|
if (expectedState == state) {
|
||||||
|
@ -22,6 +22,8 @@ import com.google.android.exoplayer2.Player;
|
|||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.Timeline.Period;
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
import com.google.android.exoplayer2.Timeline.Window;
|
import com.google.android.exoplayer2.Timeline.Window;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/** Unit test for {@link Timeline}. */
|
/** Unit test for {@link Timeline}. */
|
||||||
public final class TimelineAsserts {
|
public final class TimelineAsserts {
|
||||||
@ -48,7 +50,8 @@ public final class TimelineAsserts {
|
|||||||
* @param expectedWindowTags A list of expected window tags. If a tag is unknown or not important
|
* @param expectedWindowTags A list of expected window tags. If a tag is unknown or not important
|
||||||
* {@code null} can be passed to skip this window.
|
* {@code null} can be passed to skip this window.
|
||||||
*/
|
*/
|
||||||
public static void assertWindowTags(Timeline timeline, Object... expectedWindowTags) {
|
public static void assertWindowTags(
|
||||||
|
Timeline timeline, @NullableType Object... expectedWindowTags) {
|
||||||
Window window = new Window();
|
Window window = new Window();
|
||||||
assertThat(timeline.getWindowCount()).isEqualTo(expectedWindowTags.length);
|
assertThat(timeline.getWindowCount()).isEqualTo(expectedWindowTags.length);
|
||||||
for (int i = 0; i < timeline.getWindowCount(); i++) {
|
for (int i = 0; i < timeline.getWindowCount(); i++) {
|
||||||
@ -140,8 +143,9 @@ public final class TimelineAsserts {
|
|||||||
expectedWindowIndex++;
|
expectedWindowIndex++;
|
||||||
}
|
}
|
||||||
assertThat(period.windowIndex).isEqualTo(expectedWindowIndex);
|
assertThat(period.windowIndex).isEqualTo(expectedWindowIndex);
|
||||||
assertThat(timeline.getIndexOfPeriod(period.uid)).isEqualTo(i);
|
Object periodUid = Assertions.checkNotNull(period.uid);
|
||||||
assertThat(timeline.getUidOfPeriod(i)).isEqualTo(period.uid);
|
assertThat(timeline.getIndexOfPeriod(periodUid)).isEqualTo(i);
|
||||||
|
assertThat(timeline.getUidOfPeriod(i)).isEqualTo(periodUid);
|
||||||
for (int repeatMode : REPEAT_MODES) {
|
for (int repeatMode : REPEAT_MODES) {
|
||||||
if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) {
|
if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) {
|
||||||
assertThat(timeline.getNextPeriodIndex(i, period, window, repeatMode, false))
|
assertThat(timeline.getNextPeriodIndex(i, period, window, repeatMode, false))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user