Start fixing nullness in testutil

PiperOrigin-RevId: 292340530
This commit is contained in:
olly 2020-01-30 15:05:32 +00:00 committed by Oliver Woodman
parent ff822ff9fd
commit 7c8a54c6d0
23 changed files with 175 additions and 112 deletions

View File

@ -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,

View File

@ -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()

View File

@ -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);

View File

@ -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();

View File

@ -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);
} }

View File

@ -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);
} }
} }

View 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);
} }

View File

@ -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.

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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();

View File

@ -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.
} }

View File

@ -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;

View File

@ -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;

View File

@ -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 {
/** /**

View File

@ -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());

View File

@ -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;
} }

View File

@ -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];

View File

@ -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 {
/** /**

View File

@ -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();
} }

View File

@ -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) {

View File

@ -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))