mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Create a DumpFileAsserts from the dumpfile logic in FakeExtractorOutput
Also use it to replace the same logic in CapturingAudioSink PiperOrigin-RevId: 325969455
This commit is contained in:
parent
361e5d9326
commit
da4d55635c
6 changed files with 130 additions and 128 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
* <p>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<Dumper.Dumpable> interceptedData;
|
||||
@Nullable private ByteBuffer currentBuffer;
|
||||
|
||||
|
|
@ -98,30 +82,6 @@ public final class CapturingAudioSink extends ForwardingAudioSink implements Dum
|
|||
super.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that dump of this sink is equal to expected dump which is read from {@code dumpFile}.
|
||||
*
|
||||
* <p>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++) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
* <p>Allows the golden files to be easily updated with new data (see more info in the docs on
|
||||
* {@link #DUMP_FILE_ACTION}).
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}.
|
||||
*
|
||||
* <p>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<FakeTrackOutput> trackOutputs;
|
||||
private final FakeTrackOutput.Factory trackOutputFactory;
|
||||
|
||||
|
|
@ -124,44 +84,6 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that dump of this {@link FakeExtractorOutput} is equal to expected dump which is read
|
||||
* from {@code dumpFile}.
|
||||
*
|
||||
* <p>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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue