diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java index ccd0da4e19..c3c7b00149 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource; import com.google.android.exoplayer2.testutil.CapturingAudioSink; +import com.google.android.exoplayer2.testutil.DumpFileAsserts; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import org.junit.Before; import org.junit.Test; @@ -80,8 +81,8 @@ public class FlacPlaybackTest { throw testPlaybackRunnable.playbackException; } - audioSink.assertOutput( - ApplicationProvider.getApplicationContext(), fileName + ".audiosink.dump"); + DumpFileAsserts.assertOutput( + ApplicationProvider.getApplicationContext(), audioSink, fileName + ".audiosink.dump"); } private static class TestPlaybackRunnable implements Player.EventListener, Runnable { diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/WebvttExtractorTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/WebvttExtractorTest.java index 5f1169e222..5da804a996 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/WebvttExtractorTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/WebvttExtractorTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.testutil.DumpFileAsserts; import com.google.android.exoplayer2.testutil.FakeExtractorInput; import com.google.android.exoplayer2.testutil.FakeExtractorOutput; import com.google.android.exoplayer2.testutil.TestUtil; @@ -83,8 +84,10 @@ public class WebvttExtractorTest { // The output has a ~5s sampleTime and a large, negative subsampleOffset because the cue // timestamps are ~10 days ahead of the PTS (due to wrapping) so the offset is used to ensure // they're rendered at the right time. - output.assertOutput( - ApplicationProvider.getApplicationContext(), "webvtt/with_x-timestamp-map_header.dump"); + DumpFileAsserts.assertOutput( + ApplicationProvider.getApplicationContext(), + output, + "webvtt/with_x-timestamp-map_header.dump"); } private static boolean sniffData(byte[] data) throws IOException { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CapturingAudioSink.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CapturingAudioSink.java index ead5bd24d9..bf1ffdce0e 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CapturingAudioSink.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CapturingAudioSink.java @@ -15,18 +15,11 @@ */ package com.google.android.exoplayer2.testutil; -import static com.google.common.truth.Truth.assertWithMessage; - -import android.content.Context; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.ForwardingAudioSink; -import com.google.android.exoplayer2.util.Assertions; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -35,15 +28,6 @@ import java.util.List; /** A {@link ForwardingAudioSink} that captures configuration, discontinuity and buffer events. */ public final class CapturingAudioSink extends ForwardingAudioSink implements Dumper.Dumpable { - /** - * If true, makes {@link #assertOutput(Context, String)} method write the output to a file, rather - * than validating that the output matches the dump file. - * - *
The output file is written to the test apk's external storage directory, which is typically:
- * {@code /sdcard/Android/data/${package-under-test}.test/files/}.
- */
- private static final boolean WRITE_DUMP = false;
-
private final List If assertion fails because of an intended change in the output or a new dump file needs to
- * be created, set {@link #WRITE_DUMP} flag to true and run the test again. Instead of assertion,
- * actual dump will be written to {@code dumpFile}. This new dump file needs to be copied to the
- * project, {@code library/src/androidTest/assets} folder manually.
- */
- public void assertOutput(Context context, String dumpFile) throws IOException {
- String actual = new Dumper().add(this).toString();
-
- if (WRITE_DUMP) {
- File directory = context.getExternalFilesDir(null);
- File file = new File(directory, dumpFile);
- Assertions.checkStateNotNull(file.getParentFile()).mkdirs();
- PrintWriter out = new PrintWriter(file);
- out.print(actual);
- out.close();
- } else {
- String expected = TestUtil.getString(context, dumpFile);
- assertWithMessage(dumpFile).that(actual).isEqualTo(expected);
- }
- }
-
@Override
public void dump(Dumper dumper) {
for (int i = 0; i < interceptedData.size(); i++) {
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/DumpFileAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DumpFileAsserts.java
new file mode 100644
index 0000000000..42884ec6f4
--- /dev/null
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DumpFileAsserts.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer2.testutil;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Context;
+import androidx.annotation.IntDef;
+import com.google.android.exoplayer2.util.Assertions;
+import com.google.common.base.StandardSystemProperty;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Helper class to enable assertions based on golden-data dump files.
+ *
+ * Allows the golden files to be easily updated with new data (see more info in the docs on
+ * {@link #DUMP_FILE_ACTION}).
+ *
+ * Compatible with {@link Dumper.Dumpable} but can also be used directly with Strings generated
+ * through different means.
+ */
+public class DumpFileAsserts {
+
+ private static final String DUMP_UPDATE_INSTRUCTIONS =
+ "To update the dump file, change DumpFileAsserts#DUMP_FILE_ACTION to WRITE_TO_LOCAL (for"
+ + " Robolectric tests) or WRITE_TO_DEVICE (for instrumentation tests) and re-run the"
+ + " test.";
+
+ /** Possible actions to take with the dumps passed to {@link #assertOutput}. */
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ flag = true,
+ value = {COMPARE_WITH_EXISTING, WRITE_TO_LOCAL, WRITE_TO_DEVICE})
+ private @interface DumpFilesAction {}
+ /** Compare output with existing dump file. */
+ private static final int COMPARE_WITH_EXISTING = 0;
+ /**
+ * Write output to the project folder {@code testdata/src/test}.
+ *
+ * Enabling this option works when tests are run in Android Studio. It may not work when the
+ * tests are run in another environment.
+ */
+ private static final int WRITE_TO_LOCAL = 1;
+ /** Write output to folder {@code /storage/emulated/0/Android/data} of device. */
+ private static final int WRITE_TO_DEVICE = 1 << 1;
+
+ @DumpFilesAction private static final int DUMP_FILE_ACTION = COMPARE_WITH_EXISTING;
+
+ private DumpFileAsserts() {}
+
+ public static void assertOutput(Context context, Dumper.Dumpable actual, String dumpFile)
+ throws IOException {
+ assertOutput(context, new Dumper().add(actual).toString(), dumpFile);
+ }
+
+ /**
+ * Asserts that {@code actual} is equal to the contents of {@code dumpFile}.
+ *
+ * If the assertion fails because of an intended change in the output or a new dump file needs
+ * to be created, set {@link #DUMP_FILE_ACTION} to {@link #WRITE_TO_LOCAL} for local tests and to
+ * {@link #WRITE_TO_DEVICE} for instrumentation tests, and run the test again. Instead of
+ * assertion, {@code actual} will be written to {@code dumpFile}. For instrumentation tests, this
+ * new dump file needs to be copied to the project {@code testdata/src/test} folder manually.
+ */
+ public static void assertOutput(Context context, String actual, String dumpFile)
+ throws IOException {
+ if (DUMP_FILE_ACTION == COMPARE_WITH_EXISTING) {
+ String expected;
+ try {
+ expected = TestUtil.getString(context, dumpFile);
+ } catch (FileNotFoundException e) {
+ throw new IOException("Dump file not found. " + DUMP_UPDATE_INSTRUCTIONS, e);
+ }
+ assertWithMessage(
+ "Actual data doesn't match dump file: %s\n%s", dumpFile, DUMP_UPDATE_INSTRUCTIONS)
+ .that(actual)
+ .isEqualTo(expected);
+ } else {
+ File file =
+ DUMP_FILE_ACTION == WRITE_TO_LOCAL
+ ? new File(StandardSystemProperty.USER_DIR.value(), "../../testdata/src/test")
+ : context.getExternalFilesDir(null);
+ file = new File(file, dumpFile);
+ Assertions.checkStateNotNull(file.getParentFile()).mkdirs();
+ PrintWriter out = new PrintWriter(file);
+ out.print(actual);
+ out.close();
+ }
+ }
+}
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java
index 7411016177..c396e41f4a 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java
@@ -326,9 +326,11 @@ public final class ExtractorAsserts {
FakeExtractorOutput extractorOutput =
consumeTestData(extractor, input, 0, true, deduplicateConsecutiveFormats);
if (simulateUnknownLength) {
- extractorOutput.assertOutput(context, dumpFilesPrefix + UNKNOWN_LENGTH_EXTENSION);
+ DumpFileAsserts.assertOutput(
+ context, extractorOutput, dumpFilesPrefix + UNKNOWN_LENGTH_EXTENSION);
} else {
- extractorOutput.assertOutput(context, dumpFilesPrefix + ".0" + DUMP_EXTENSION);
+ DumpFileAsserts.assertOutput(
+ context, extractorOutput, dumpFilesPrefix + ".0" + DUMP_EXTENSION);
}
// Seeking to (timeUs=0, position=0) should always work, and cause the same data to be output.
@@ -336,9 +338,11 @@ public final class ExtractorAsserts {
input.reset();
consumeTestData(extractor, input, /* timeUs= */ 0, extractorOutput, false);
if (simulateUnknownLength) {
- extractorOutput.assertOutput(context, dumpFilesPrefix + UNKNOWN_LENGTH_EXTENSION);
+ DumpFileAsserts.assertOutput(
+ context, extractorOutput, dumpFilesPrefix + UNKNOWN_LENGTH_EXTENSION);
} else {
- extractorOutput.assertOutput(context, dumpFilesPrefix + ".0" + DUMP_EXTENSION);
+ DumpFileAsserts.assertOutput(
+ context, extractorOutput, dumpFilesPrefix + ".0" + DUMP_EXTENSION);
}
SeekMap seekMap = Assertions.checkNotNull(extractorOutput.seekMap);
@@ -357,9 +361,11 @@ public final class ExtractorAsserts {
extractorOutput.clearTrackOutputs();
consumeTestData(extractor, input, timeUs, extractorOutput, false);
if (simulateUnknownLength && timeUs == 0) {
- extractorOutput.assertOutput(context, dumpFilesPrefix + UNKNOWN_LENGTH_EXTENSION);
+ DumpFileAsserts.assertOutput(
+ context, extractorOutput, dumpFilesPrefix + UNKNOWN_LENGTH_EXTENSION);
} else {
- extractorOutput.assertOutput(context, dumpFilesPrefix + '.' + j + DUMP_EXTENSION);
+ DumpFileAsserts.assertOutput(
+ context, extractorOutput, dumpFilesPrefix + '.' + j + DUMP_EXTENSION);
}
}
}
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java
index 6df4fc4dd2..6253ae4daa 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java
@@ -16,57 +16,17 @@
package com.google.android.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-import android.content.Context;
import android.util.SparseArray;
-import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.SeekMap;
-import com.google.android.exoplayer2.util.Assertions;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** A fake {@link ExtractorOutput}. */
public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpable {
- private static final String DUMP_UPDATE_INSTRUCTIONS =
- "To update the dump file, change FakeExtractorOutput#DUMP_FILE_ACTION to WRITE_TO_LOCAL (for"
- + " Robolectric tests) or WRITE_TO_DEVICE (for instrumentation tests) and re-run the"
- + " test.";
-
- /**
- * Possible actions to take with the dumps generated from this {@code FakeExtractorOutput} in
- * {@link #assertOutput(Context, String)}.
- */
- @Documented
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- flag = true,
- value = {COMPARE_WITH_EXISTING, WRITE_TO_LOCAL, WRITE_TO_DEVICE})
- private @interface DumpFilesAction {}
- /** Compare output with existing dump file. */
- private static final int COMPARE_WITH_EXISTING = 0;
- /**
- * Write output to the project folder {@code testdata/src/test/assets}.
- *
- * Enabling this option works when tests are run in Android Studio. It may not work when the
- * tests are run in another environment.
- */
- private static final int WRITE_TO_LOCAL = 1;
- /** Write output to folder {@code /storage/emulated/0/Android/data} of device. */
- private static final int WRITE_TO_DEVICE = 1 << 1;
-
- @DumpFilesAction private static final int DUMP_FILE_ACTION = COMPARE_WITH_EXISTING;
-
public final SparseArray If assertion fails because of an intended change in the output or a new dump file needs to
- * be created, set {@link #DUMP_FILE_ACTION} to {@link #WRITE_TO_LOCAL} for local tests and to
- * {@link #WRITE_TO_DEVICE} for instrumentation tests, and run the test again. Instead of
- * assertion, actual dump will be written to {@code dumpFile}. For instrumentation tests, this new
- * dump file needs to be copied to the project {@code testdata/src/test/assets} folder manually.
- */
- public void assertOutput(Context context, String dumpFile) throws IOException {
- String actual = new Dumper().add(this).toString();
-
- if (DUMP_FILE_ACTION == COMPARE_WITH_EXISTING) {
- String expected;
- try {
- expected = TestUtil.getString(context, dumpFile);
- } catch (FileNotFoundException e) {
- throw new IOException("Dump file not found. " + DUMP_UPDATE_INSTRUCTIONS, e);
- }
- assertWithMessage(
- "Extractor output doesn't match dump file: %s\n%s",
- dumpFile, DUMP_UPDATE_INSTRUCTIONS)
- .that(actual)
- .isEqualTo(expected);
- } else {
- File file =
- DUMP_FILE_ACTION == WRITE_TO_LOCAL
- ? new File(System.getProperty("user.dir"), "../../testdata/src/test/assets")
- : context.getExternalFilesDir(null);
- file = new File(file, dumpFile);
- Assertions.checkStateNotNull(file.getParentFile()).mkdirs();
- PrintWriter out = new PrintWriter(file);
- out.print(actual);
- out.close();
- }
- }
-
@Override
public void dump(Dumper dumper) {
if (seekMap != null) {