Make tests independent

PiperOrigin-RevId: 289521837
This commit is contained in:
andrewlewis 2020-01-13 22:38:18 +00:00 committed by Oliver Woodman
parent ccce9948a9
commit 4c74f3cffd
37 changed files with 390 additions and 746 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,13 +16,15 @@
package com.google.android.exoplayer2.extractor;
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
import static com.google.common.truth.Truth.assertThat;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.id3.ApicFrame;
import com.google.android.exoplayer2.metadata.id3.CommentFrame;
import com.google.android.exoplayer2.metadata.id3.Id3DecoderTest;
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
import java.io.IOException;
import org.junit.Test;
@ -41,7 +43,7 @@ public final class Id3PeekerTest {
.setData(new byte[] {1, 'I', 'D', '3', 2, 3, 4, 5, 6, 7, 8, 9, 10})
.build();
Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
@Nullable Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
assertThat(metadata).isNull();
}
@ -49,17 +51,13 @@ public final class Id3PeekerTest {
public void testPeekId3Data_returnId3Tag_ifId3TagPresent()
throws IOException, InterruptedException {
Id3Peeker id3Peeker = new Id3Peeker();
FakeExtractorInput input =
new FakeExtractorInput.Builder()
.setData(getByteArray(ApplicationProvider.getApplicationContext(), "id3/apic.id3"))
.build();
byte[] rawId3 =
Id3DecoderTest.buildSingleFrameTag(
"APIC",
new byte[] {
3, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 0, 16, 72, 101, 108, 108, 111, 32,
87, 111, 114, 108, 100, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
});
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(rawId3).build();
Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
@Nullable Metadata metadata = id3Peeker.peekId3Data(input, /* id3FramePredicate= */ null);
assertThat(metadata).isNotNull();
assertThat(metadata.length()).isEqualTo(1);
ApicFrame apicFrame = (ApicFrame) metadata.get(0);
@ -74,28 +72,18 @@ public final class Id3PeekerTest {
public void testPeekId3Data_returnId3TagAccordingToGivenPredicate_ifId3TagPresent()
throws IOException, InterruptedException {
Id3Peeker id3Peeker = new Id3Peeker();
FakeExtractorInput input =
new FakeExtractorInput.Builder()
.setData(getByteArray(ApplicationProvider.getApplicationContext(), "id3/comm_apic.id3"))
.build();
byte[] rawId3 =
Id3DecoderTest.buildMultiFramesTag(
new Id3DecoderTest.FrameSpec(
"COMM",
new byte[] {
3, 101, 110, 103, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 0, 116,
101, 120, 116, 0
}),
new Id3DecoderTest.FrameSpec(
"APIC",
new byte[] {
3, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 0, 16, 72, 101, 108, 108, 111,
32, 87, 111, 114, 108, 100, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
}));
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(rawId3).build();
@Nullable
Metadata metadata =
id3Peeker.peekId3Data(
input,
(majorVersion, id0, id1, id2, id3) ->
id0 == 'C' && id1 == 'O' && id2 == 'M' && id3 == 'M');
assertThat(metadata).isNotNull();
assertThat(metadata.length()).isEqualTo(1);
CommentFrame commentFrame = (CommentFrame) metadata.get(0);

View File

@ -15,9 +15,11 @@
*/
package com.google.android.exoplayer2.extractor.ogg;
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.ExtractorInput;
@ -34,7 +36,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public final class DefaultOggSeekerTest {
private final Random random = new Random(0);
private final Random random = new Random(/* seed= */ 0);
@Test
public void testSetupWithUnsetEndPositionFails() {
@ -53,113 +55,24 @@ public final class DefaultOggSeekerTest {
}
@Test
public void testSeeking() throws IOException, InterruptedException {
Random random = new Random(0);
for (int i = 0; i < 100; i++) {
testSeeking(random);
}
}
public void testSeeking() throws Exception {
byte[] data =
getByteArray(ApplicationProvider.getApplicationContext(), "ogg/random_1000_pages");
int granuleCount = 49269395;
int firstPayloadPageSize = 2023;
int firstPayloadPageGranuleCount = 57058;
int lastPayloadPageSize = 282;
int lastPayloadPageGranuleCount = 20806;
@Test
public void testSkipToNextPage() throws Exception {
FakeExtractorInput extractorInput =
OggTestData.createInput(
TestUtil.joinByteArrays(
TestUtil.buildTestData(4000, random),
new byte[] {'O', 'g', 'g', 'S'},
TestUtil.buildTestData(4000, random)),
false);
skipToNextPage(extractorInput);
assertThat(extractorInput.getPosition()).isEqualTo(4000);
}
@Test
public void testSkipToNextPageOverlap() throws Exception {
FakeExtractorInput extractorInput =
OggTestData.createInput(
TestUtil.joinByteArrays(
TestUtil.buildTestData(2046, random),
new byte[] {'O', 'g', 'g', 'S'},
TestUtil.buildTestData(4000, random)),
false);
skipToNextPage(extractorInput);
assertThat(extractorInput.getPosition()).isEqualTo(2046);
}
@Test
public void testSkipToNextPageInputShorterThanPeekLength() throws Exception {
FakeExtractorInput extractorInput =
OggTestData.createInput(
TestUtil.joinByteArrays(new byte[] {'x', 'O', 'g', 'g', 'S'}), false);
skipToNextPage(extractorInput);
assertThat(extractorInput.getPosition()).isEqualTo(1);
}
@Test
public void testSkipToNextPageNoMatch() throws Exception {
FakeExtractorInput extractorInput =
OggTestData.createInput(new byte[] {'g', 'g', 'S', 'O', 'g', 'g'}, false);
try {
skipToNextPage(extractorInput);
fail();
} catch (EOFException e) {
// expected
}
}
@Test
public void testReadGranuleOfLastPage() throws IOException, InterruptedException {
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
TestUtil.buildTestData(100, random),
OggTestData.buildOggHeader(0x00, 20000, 66, 3),
TestUtil.createByteArray(254, 254, 254), // laces
TestUtil.buildTestData(3 * 254, random),
OggTestData.buildOggHeader(0x00, 40000, 67, 3),
TestUtil.createByteArray(254, 254, 254), // laces
TestUtil.buildTestData(3 * 254, random),
OggTestData.buildOggHeader(0x05, 60000, 68, 3),
TestUtil.createByteArray(254, 254, 254), // laces
TestUtil.buildTestData(3 * 254, random)),
false);
assertReadGranuleOfLastPage(input, 60000);
}
@Test
public void testReadGranuleOfLastPageAfterLastHeader() throws IOException, InterruptedException {
FakeExtractorInput input = OggTestData.createInput(TestUtil.buildTestData(100, random), false);
try {
assertReadGranuleOfLastPage(input, 60000);
fail();
} catch (EOFException e) {
// Ignored.
}
}
@Test
public void testReadGranuleOfLastPageWithUnboundedLength()
throws IOException, InterruptedException {
FakeExtractorInput input = OggTestData.createInput(new byte[0], true);
try {
assertReadGranuleOfLastPage(input, 60000);
fail();
} catch (IllegalArgumentException e) {
// Ignored.
}
}
private void testSeeking(Random random) throws IOException, InterruptedException {
OggTestFile testFile = OggTestFile.generate(random, 1000);
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(testFile.data).build();
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(data).build();
TestStreamReader streamReader = new TestStreamReader();
DefaultOggSeeker oggSeeker =
new DefaultOggSeeker(
/* streamReader= */ streamReader,
streamReader,
/* payloadStartPosition= */ 0,
/* payloadEndPosition= */ testFile.data.length,
/* firstPayloadPageSize= */ testFile.firstPayloadPageSize,
/* firstPayloadPageGranulePosition= */ testFile.firstPayloadPageGranuleCount,
/* payloadEndPosition= */ data.length,
firstPayloadPageSize,
/* firstPayloadPageGranulePosition= */ firstPayloadPageGranuleCount,
/* firstPayloadPageIsLastPage= */ false);
OggPageHeader pageHeader = new OggPageHeader();
@ -177,30 +90,30 @@ public final class DefaultOggSeekerTest {
assertThat(input.getPosition()).isEqualTo(0);
// Test granule 0 from file end.
granule = seekTo(input, oggSeeker, 0, testFile.data.length - 1);
granule = seekTo(input, oggSeeker, 0, data.length - 1);
assertThat(granule).isEqualTo(0);
assertThat(input.getPosition()).isEqualTo(0);
// Test last granule.
granule = seekTo(input, oggSeeker, testFile.granuleCount - 1, 0);
assertThat(granule).isEqualTo(testFile.granuleCount - testFile.lastPayloadPageGranuleCount);
assertThat(input.getPosition()).isEqualTo(testFile.data.length - testFile.lastPayloadPageSize);
granule = seekTo(input, oggSeeker, granuleCount - 1, 0);
assertThat(granule).isEqualTo(granuleCount - lastPayloadPageGranuleCount);
assertThat(input.getPosition()).isEqualTo(data.length - lastPayloadPageSize);
for (int i = 0; i < 100; i += 1) {
long targetGranule = random.nextInt(testFile.granuleCount);
int initialPosition = random.nextInt(testFile.data.length);
long targetGranule = random.nextInt(granuleCount);
int initialPosition = random.nextInt(data.length);
granule = seekTo(input, oggSeeker, targetGranule, initialPosition);
long currentPosition = input.getPosition();
int currentPosition = (int) input.getPosition();
if (granule == 0) {
assertThat(currentPosition).isEqualTo(0);
} else {
int previousPageStart = testFile.findPreviousPageStart(currentPosition);
int previousPageStart = findPreviousPageStart(data, currentPosition);
input.setPosition(previousPageStart);
pageHeader.populate(input, false);
assertThat(granule).isEqualTo(pageHeader.granulePosition);
}
input.setPosition((int) currentPosition);
input.setPosition(currentPosition);
pageHeader.populate(input, false);
// The target granule should be within the current page.
assertThat(granule).isAtMost(targetGranule);
@ -208,6 +121,85 @@ public final class DefaultOggSeekerTest {
}
}
@Test
public void testSkipToNextPage() throws Exception {
FakeExtractorInput extractorInput =
createInput(
TestUtil.joinByteArrays(
TestUtil.buildTestData(4000, random),
new byte[] {'O', 'g', 'g', 'S'},
TestUtil.buildTestData(4000, random)),
/* simulateUnknownLength= */ false);
skipToNextPage(extractorInput);
assertThat(extractorInput.getPosition()).isEqualTo(4000);
}
@Test
public void testSkipToNextPageOverlap() throws Exception {
FakeExtractorInput extractorInput =
createInput(
TestUtil.joinByteArrays(
TestUtil.buildTestData(2046, random),
new byte[] {'O', 'g', 'g', 'S'},
TestUtil.buildTestData(4000, random)),
/* simulateUnknownLength= */ false);
skipToNextPage(extractorInput);
assertThat(extractorInput.getPosition()).isEqualTo(2046);
}
@Test
public void testSkipToNextPageInputShorterThanPeekLength() throws Exception {
FakeExtractorInput extractorInput =
createInput(
TestUtil.joinByteArrays(new byte[] {'x', 'O', 'g', 'g', 'S'}),
/* simulateUnknownLength= */ false);
skipToNextPage(extractorInput);
assertThat(extractorInput.getPosition()).isEqualTo(1);
}
@Test
public void testSkipToNextPageNoMatch() throws Exception {
FakeExtractorInput extractorInput =
createInput(new byte[] {'g', 'g', 'S', 'O', 'g', 'g'}, /* simulateUnknownLength= */ false);
try {
skipToNextPage(extractorInput);
fail();
} catch (EOFException e) {
// expected
}
}
@Test
public void testReadGranuleOfLastPage() throws IOException, InterruptedException {
// This test stream has three headers with granule numbers 20000, 40000 and 60000.
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/three_headers");
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ false);
assertReadGranuleOfLastPage(input, 60000);
}
@Test
public void testReadGranuleOfLastPageAfterLastHeader() throws Exception {
FakeExtractorInput input =
createInput(TestUtil.buildTestData(100, random), /* simulateUnknownLength= */ false);
try {
assertReadGranuleOfLastPage(input, 60000);
fail();
} catch (EOFException e) {
// Ignored.
}
}
@Test
public void testReadGranuleOfLastPageWithUnboundedLength() throws Exception {
FakeExtractorInput input = createInput(new byte[0], /* simulateUnknownLength= */ true);
try {
assertReadGranuleOfLastPage(input, 60000);
fail();
} catch (IllegalArgumentException e) {
// Ignored.
}
}
private static void skipToNextPage(ExtractorInput extractorInput)
throws IOException, InterruptedException {
DefaultOggSeeker oggSeeker =
@ -248,6 +240,15 @@ public final class DefaultOggSeekerTest {
}
}
private static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
return new FakeExtractorInput.Builder()
.setData(data)
.setSimulateIOErrors(true)
.setSimulateUnknownLength(simulateUnknownLength)
.setSimulatePartialReads(true)
.build();
}
private static long seekTo(
FakeExtractorInput input, DefaultOggSeeker oggSeeker, long targetGranule, int initialPosition)
throws IOException, InterruptedException {
@ -264,6 +265,16 @@ public final class DefaultOggSeekerTest {
return -(nextSeekPosition + 2);
}
private static int findPreviousPageStart(byte[] data, int position) {
for (int i = position - 4; i >= 0; i--) {
if (data[i] == 'O' && data[i + 1] == 'g' && data[i + 2] == 'g' && data[i + 3] == 'S') {
return i;
}
}
fail();
return -1;
}
private static class TestStreamReader extends StreamReader {
@Override
protected long preparePayload(ParsableByteArray packet) {

View File

@ -15,12 +15,13 @@
*/
package com.google.android.exoplayer2.extractor.ogg;
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.testutil.ExtractorAsserts;
import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory;
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -53,51 +54,38 @@ public final class OggExtractorTest {
@Test
public void testSniffVorbis() throws Exception {
byte[] data =
TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x02, 0, 1000, 1),
TestUtil.createByteArray(7), // Laces
new byte[] {0x01, 'v', 'o', 'r', 'b', 'i', 's'});
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/vorbis_header");
assertSniff(data, /* expectedResult= */ true);
}
@Test
public void testSniffFlac() throws Exception {
byte[] data =
TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x02, 0, 1000, 1),
TestUtil.createByteArray(5), // Laces
new byte[] {0x7F, 'F', 'L', 'A', 'C'});
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/flac_header");
assertSniff(data, /* expectedResult= */ true);
}
@Test
public void testSniffFailsOpusFile() throws Exception {
byte[] data =
TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x02, 0, 1000, 0x00), new byte[] {'O', 'p', 'u', 's'});
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/opus_header");
assertSniff(data, /* expectedResult= */ false);
}
@Test
public void testSniffFailsInvalidOggHeader() throws Exception {
byte[] data = OggTestData.buildOggHeader(0x00, 0, 1000, 0x00);
byte[] data =
getByteArray(ApplicationProvider.getApplicationContext(), "ogg/invalid_ogg_header");
assertSniff(data, /* expectedResult= */ false);
}
@Test
public void testSniffInvalidHeader() throws Exception {
byte[] data =
TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x02, 0, 1000, 1),
TestUtil.createByteArray(7), // Laces
new byte[] {0x7F, 'X', 'o', 'r', 'b', 'i', 's'});
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/invalid_header");
assertSniff(data, /* expectedResult= */ false);
}
@Test
public void testSniffFailsEOF() throws Exception {
byte[] data = OggTestData.buildOggHeader(0x02, 0, 1000, 0x00);
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/eof_header");
assertSniff(data, /* expectedResult= */ false);
}

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.extractor.ogg;
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.core.app.ApplicationProvider;
@ -25,7 +26,6 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -35,14 +35,8 @@ public final class OggPacketTest {
private static final String TEST_FILE = "ogg/bear.opus";
private Random random;
private OggPacket oggPacket;
@Before
public void setUp() throws Exception {
random = new Random(0);
oggPacket = new OggPacket();
}
private final Random random = new Random(/* seed= */ 0);
private final OggPacket oggPacket = new OggPacket();
@Test
public void testReadPacketsWithEmptyPage() throws Exception {
@ -50,26 +44,10 @@ public final class OggPacketTest {
byte[] secondPacket = TestUtil.buildTestData(272, random);
byte[] thirdPacket = TestUtil.buildTestData(256, random);
byte[] fourthPacket = TestUtil.buildTestData(271, random);
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
// First page with a single packet.
OggTestData.buildOggHeader(0x02, 0, 1000, 0x01),
TestUtil.createByteArray(0x08), // Laces
firstPacket,
// Second page with a single packet.
OggTestData.buildOggHeader(0x00, 16, 1001, 0x02),
TestUtil.createByteArray(0xFF, 0x11), // Laces
secondPacket,
// Third page with zero packets.
OggTestData.buildOggHeader(0x00, 16, 1002, 0x00),
// Fourth page with two packets.
OggTestData.buildOggHeader(0x04, 128, 1003, 0x04),
TestUtil.createByteArray(0xFF, 0x01, 0xFF, 0x10), // Laces
thirdPacket,
fourthPacket),
true);
createInput(
getByteArray(
ApplicationProvider.getApplicationContext(), "ogg/four_packets_with_empty_page"));
assertReadPacket(input, firstPacket);
assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isTrue();
@ -113,15 +91,11 @@ public final class OggPacketTest {
public void testReadPacketWithZeroSizeTerminator() throws Exception {
byte[] firstPacket = TestUtil.buildTestData(255, random);
byte[] secondPacket = TestUtil.buildTestData(8, random);
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x06, 0, 1000, 0x04),
TestUtil.createByteArray(0xFF, 0x00, 0x00, 0x08), // Laces.
firstPacket,
secondPacket),
true);
createInput(
getByteArray(
ApplicationProvider.getApplicationContext(),
"ogg/packet_with_zero_size_terminator"));
assertReadPacket(input, firstPacket);
assertReadPacket(input, secondPacket);
@ -131,19 +105,11 @@ public final class OggPacketTest {
@Test
public void testReadContinuedPacketOverTwoPages() throws Exception {
byte[] firstPacket = TestUtil.buildTestData(518);
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
// First page.
OggTestData.buildOggHeader(0x02, 0, 1000, 0x02),
TestUtil.createByteArray(0xFF, 0xFF), // Laces.
Arrays.copyOf(firstPacket, 510),
// Second page (continued packet).
OggTestData.buildOggHeader(0x05, 10, 1001, 0x01),
TestUtil.createByteArray(0x08), // Laces.
Arrays.copyOfRange(firstPacket, 510, 510 + 8)),
true);
createInput(
getByteArray(
ApplicationProvider.getApplicationContext(),
"ogg/continued_packet_over_two_pages"));
assertReadPacket(input, firstPacket);
assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
@ -156,27 +122,11 @@ public final class OggPacketTest {
@Test
public void testReadContinuedPacketOverFourPages() throws Exception {
byte[] firstPacket = TestUtil.buildTestData(1028);
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
// First page.
OggTestData.buildOggHeader(0x02, 0, 1000, 0x02),
TestUtil.createByteArray(0xFF, 0xFF), // Laces.
Arrays.copyOf(firstPacket, 510),
// Second page (continued packet).
OggTestData.buildOggHeader(0x01, 10, 1001, 0x01),
TestUtil.createByteArray(0xFF), // Laces.
Arrays.copyOfRange(firstPacket, 510, 510 + 255),
// Third page (continued packet).
OggTestData.buildOggHeader(0x01, 10, 1002, 0x01),
TestUtil.createByteArray(0xFF), // Laces.
Arrays.copyOfRange(firstPacket, 510 + 255, 510 + 255 + 255),
// Fourth page (continued packet).
OggTestData.buildOggHeader(0x05, 10, 1003, 0x01),
TestUtil.createByteArray(0x08), // Laces.
Arrays.copyOfRange(firstPacket, 510 + 255 + 255, 510 + 255 + 255 + 8)),
true);
createInput(
getByteArray(
ApplicationProvider.getApplicationContext(),
"ogg/continued_packet_over_four_pages"));
assertReadPacket(input, firstPacket);
assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
@ -189,15 +139,10 @@ public final class OggPacketTest {
@Test
public void testReadDiscardContinuedPacketAtStart() throws Exception {
byte[] pageBody = TestUtil.buildTestData(256 + 8);
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
// Page with a continued packet at start.
OggTestData.buildOggHeader(0x01, 10, 1001, 0x03),
TestUtil.createByteArray(255, 1, 8), // Laces.
pageBody),
true);
createInput(
getByteArray(
ApplicationProvider.getApplicationContext(), "ogg/continued_packet_at_start"));
// Expect the first partial packet to be discarded.
assertReadPacket(input, Arrays.copyOfRange(pageBody, 256, 256 + 8));
@ -209,20 +154,11 @@ public final class OggPacketTest {
byte[] firstPacket = TestUtil.buildTestData(8, random);
byte[] secondPacket = TestUtil.buildTestData(8, random);
byte[] thirdPacket = TestUtil.buildTestData(8, random);
FakeExtractorInput input =
OggTestData.createInput(
TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x02, 0, 1000, 0x01),
TestUtil.createByteArray(0x08), // Laces.
firstPacket,
OggTestData.buildOggHeader(0x04, 0, 1001, 0x03),
TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
secondPacket,
OggTestData.buildOggHeader(0x04, 0, 1002, 0x03),
TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
thirdPacket),
true);
createInput(
getByteArray(
ApplicationProvider.getApplicationContext(),
"ogg/zero_sized_packets_at_end_of_stream"));
assertReadPacket(input, firstPacket);
assertReadPacket(input, secondPacket);
@ -241,6 +177,15 @@ public final class OggPacketTest {
assertThat(packetCounter).isEqualTo(277);
}
private static FakeExtractorInput createInput(byte[] data) {
return new FakeExtractorInput.Builder()
.setData(data)
.setSimulateIOErrors(true)
.setSimulateUnknownLength(true)
.setSimulatePartialReads(true)
.build();
}
private void assertReadPacket(FakeExtractorInput extractorInput, byte[] expected)
throws IOException, InterruptedException {
assertThat(readPacket(extractorInput)).isTrue();

View File

@ -15,13 +15,14 @@
*/
package com.google.android.exoplayer2.extractor.ogg;
import static com.google.android.exoplayer2.testutil.TestUtil.getByteArray;
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.testutil.FakeExtractorInput;
import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -30,13 +31,12 @@ import org.junit.runner.RunWith;
public final class OggPageHeaderTest {
@Test
public void testPopulatePageHeader() throws IOException, InterruptedException {
FakeExtractorInput input = OggTestData.createInput(TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x01, 123456, 4, 2),
TestUtil.createByteArray(2, 2)
), true);
public void testPopulatePageHeader() throws Exception {
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/page_header");
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ true);
OggPageHeader header = new OggPageHeader();
populatePageHeader(input, header, false);
populatePageHeader(input, header, /* quiet= */ false);
assertThat(header.type).isEqualTo(0x01);
assertThat(header.headerSize).isEqualTo(27 + 2);
@ -50,51 +50,51 @@ public final class OggPageHeaderTest {
}
@Test
public void testPopulatePageHeaderQuiteOnExceptionLessThan27Bytes()
throws IOException, InterruptedException {
FakeExtractorInput input = OggTestData.createInput(TestUtil.createByteArray(2, 2), false);
public void testPopulatePageHeaderQuietOnExceptionLessThan27Bytes() throws Exception {
FakeExtractorInput input =
createInput(TestUtil.createByteArray(2, 2), /* simulateUnknownLength= */ false);
OggPageHeader header = new OggPageHeader();
assertThat(populatePageHeader(input, header, true)).isFalse();
assertThat(populatePageHeader(input, header, /* quiet= */ true)).isFalse();
}
@Test
public void testPopulatePageHeaderQuiteOnExceptionNotOgg()
throws IOException, InterruptedException {
byte[] headerBytes = TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x01, 123456, 4, 2),
TestUtil.createByteArray(2, 2)
);
public void testPopulatePageHeaderQuietOnExceptionNotOgg() throws Exception {
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/page_header");
// change from 'O' to 'o'
headerBytes[0] = 'o';
FakeExtractorInput input = OggTestData.createInput(headerBytes, false);
data[0] = 'o';
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ false);
OggPageHeader header = new OggPageHeader();
assertThat(populatePageHeader(input, header, true)).isFalse();
assertThat(populatePageHeader(input, header, /* quiet= */ true)).isFalse();
}
@Test
public void testPopulatePageHeaderQuiteOnExceptionWrongRevision()
throws IOException, InterruptedException {
byte[] headerBytes = TestUtil.joinByteArrays(
OggTestData.buildOggHeader(0x01, 123456, 4, 2),
TestUtil.createByteArray(2, 2)
);
public void testPopulatePageHeaderQuiteOnExceptionWrongRevision() throws Exception {
byte[] data = getByteArray(ApplicationProvider.getApplicationContext(), "ogg/page_header");
// change revision from 0 to 1
headerBytes[4] = 0x01;
FakeExtractorInput input = OggTestData.createInput(headerBytes, false);
data[4] = 0x01;
FakeExtractorInput input = createInput(data, /* simulateUnknownLength= */ false);
OggPageHeader header = new OggPageHeader();
assertThat(populatePageHeader(input, header, true)).isFalse();
assertThat(populatePageHeader(input, header, /* quiet= */ true)).isFalse();
}
private boolean populatePageHeader(FakeExtractorInput input, OggPageHeader header,
boolean quite) throws IOException, InterruptedException {
private static boolean populatePageHeader(
FakeExtractorInput input, OggPageHeader header, boolean quiet) throws Exception {
while (true) {
try {
return header.populate(input, quite);
return header.populate(input, quiet);
} catch (SimulatedIOException e) {
// ignored
}
}
}
private static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
return new FakeExtractorInput.Builder()
.setData(data)
.setSimulateIOErrors(true)
.setSimulateUnknownLength(simulateUnknownLength)
.setSimulatePartialReads(true)
.build();
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2016 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.extractor.ogg;
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
import com.google.android.exoplayer2.testutil.TestUtil;
/** Provides ogg/vorbis test data in bytes for unit tests. */
/* package */ final class OggTestData {
public static FakeExtractorInput createInput(byte[] data, boolean simulateUnknownLength) {
return new FakeExtractorInput.Builder()
.setData(data)
.setSimulateIOErrors(true)
.setSimulateUnknownLength(simulateUnknownLength)
.setSimulatePartialReads(true)
.build();
}
public static byte[] buildOggHeader(
int headerType, long granule, int pageSequenceCounter, int pageSegmentCount) {
return TestUtil.createByteArray(
0x4F,
0x67,
0x67,
0x53, // Oggs.
0x00, // Stream revision.
headerType,
(int) (granule) & 0xFF,
(int) (granule >> 8) & 0xFF,
(int) (granule >> 16) & 0xFF,
(int) (granule >> 24) & 0xFF,
(int) (granule >> 32) & 0xFF,
(int) (granule >> 40) & 0xFF,
(int) (granule >> 48) & 0xFF,
(int) (granule >> 56) & 0xFF,
0x00, // LSB of data serial number.
0x10,
0x00,
0x00, // MSB of data serial number.
(pageSequenceCounter) & 0xFF,
(pageSequenceCounter >> 8) & 0xFF,
(pageSequenceCounter >> 16) & 0xFF,
(pageSequenceCounter >> 24) & 0xFF,
0x00, // LSB of page checksum.
0x00,
0x10,
0x00, // MSB of page checksum.
pageSegmentCount);
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright (C) 2016 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.extractor.ogg;
import static org.junit.Assert.fail;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.util.ArrayList;
import java.util.Random;
/** Generates test data. */
/* package */ final class OggTestFile {
private static final int MAX_PACKET_LENGTH = 2048;
private static final int MAX_SEGMENT_COUNT = 10;
private static final int MAX_GRANULES_IN_PAGE = 100000;
public final byte[] data;
public final int granuleCount;
public final int pageCount;
public final int firstPayloadPageSize;
public final int firstPayloadPageGranuleCount;
public final int lastPayloadPageSize;
public final int lastPayloadPageGranuleCount;
private OggTestFile(
byte[] data,
int granuleCount,
int pageCount,
int firstPayloadPageSize,
int firstPayloadPageGranuleCount,
int lastPayloadPageSize,
int lastPayloadPageGranuleCount) {
this.data = data;
this.granuleCount = granuleCount;
this.pageCount = pageCount;
this.firstPayloadPageSize = firstPayloadPageSize;
this.firstPayloadPageGranuleCount = firstPayloadPageGranuleCount;
this.lastPayloadPageSize = lastPayloadPageSize;
this.lastPayloadPageGranuleCount = lastPayloadPageGranuleCount;
}
public static OggTestFile generate(Random random, int pageCount) {
ArrayList<byte[]> fileData = new ArrayList<>();
int fileSize = 0;
int granuleCount = 0;
int firstPayloadPageSize = 0;
int firstPayloadPageGranuleCount = 0;
int lastPageloadPageSize = 0;
int lastPayloadPageGranuleCount = 0;
int packetLength = -1;
for (int i = 0; i < pageCount; i++) {
int headerType = 0x00;
if (packetLength >= 0) {
headerType |= 1;
}
if (i == 0) {
headerType |= 2;
}
if (i == pageCount - 1) {
headerType |= 4;
}
int pageGranuleCount = random.nextInt(MAX_GRANULES_IN_PAGE - 1) + 1;
int pageSegmentCount = random.nextInt(MAX_SEGMENT_COUNT);
granuleCount += pageGranuleCount;
byte[] header = OggTestData.buildOggHeader(headerType, granuleCount, 0, pageSegmentCount);
fileData.add(header);
int pageSize = header.length;
byte[] laces = new byte[pageSegmentCount];
int bodySize = 0;
for (int j = 0; j < pageSegmentCount; j++) {
if (packetLength < 0) {
if (i < pageCount - 1) {
packetLength = random.nextInt(MAX_PACKET_LENGTH);
} else {
int maxPacketLength = 255 * (pageSegmentCount - j) - 1;
packetLength = random.nextInt(maxPacketLength);
}
} else if (i == pageCount - 1 && j == pageSegmentCount - 1) {
packetLength = Math.min(packetLength, 254);
}
laces[j] = (byte) Math.min(packetLength, 255);
bodySize += laces[j] & 0xFF;
packetLength -= 255;
}
fileData.add(laces);
pageSize += laces.length;
byte[] payload = TestUtil.buildTestData(bodySize, random);
fileData.add(payload);
pageSize += payload.length;
fileSize += pageSize;
if (i == 0) {
firstPayloadPageSize = pageSize;
firstPayloadPageGranuleCount = pageGranuleCount;
} else if (i == pageCount - 1) {
lastPageloadPageSize = pageSize;
lastPayloadPageGranuleCount = pageGranuleCount;
}
}
byte[] file = new byte[fileSize];
int position = 0;
for (byte[] data : fileData) {
System.arraycopy(data, 0, file, position, data.length);
position += data.length;
}
return new OggTestFile(
file,
granuleCount,
pageCount,
firstPayloadPageSize,
firstPayloadPageGranuleCount,
lastPageloadPageSize,
lastPayloadPageGranuleCount);
}
public int findPreviousPageStart(long position) {
for (int i = (int) (position - 4); i >= 0; i--) {
if (data[i] == 'O' && data[i + 1] == 'g' && data[i + 2] == 'g' && data[i + 3] == 'S') {
return i;
}
}
fail();
return -1;
}
}

View File

@ -16,8 +16,7 @@
package com.google.android.exoplayer2.mediacodec;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
@ -28,12 +27,12 @@ import android.os.HandlerThread;
import android.os.Looper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Shadows;
/** Unit tests for {@link AsynchronousMediaCodecAdapter}. */
@RunWith(AndroidJUnit4.class)
@ -87,8 +86,7 @@ public class AsynchronousMediaCodecAdapterTest {
}
@Test
public void dequeueInputBufferIndex_afterFlushCompletes_returnsNextInputBuffer()
throws InterruptedException {
public void dequeueInputBufferIndex_afterFlushCompletes_returnsNextInputBuffer() {
adapter.start();
Handler handler = new Handler(looper);
handler.post(
@ -97,13 +95,13 @@ public class AsynchronousMediaCodecAdapterTest {
handler.post(
() -> adapter.getMediaCodecCallback().onInputBufferAvailable(codec, /* index=*/ 1));
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(1);
}
@Test
public void dequeueInputBufferIndex_afterFlushCompletesWithError_throwsException()
throws InterruptedException {
public void dequeueInputBufferIndex_afterFlushCompletesWithError_throwsException() {
AtomicInteger calls = new AtomicInteger(0);
adapter.setCodecStartRunnable(
() -> {
@ -114,7 +112,8 @@ public class AsynchronousMediaCodecAdapterTest {
adapter.start();
adapter.flush();
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThrows(
IllegalStateException.class,
() -> {
@ -138,7 +137,7 @@ public class AsynchronousMediaCodecAdapterTest {
adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 0, outBufferInfo);
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(0);
assertThat(areEqual(bufferInfo, outBufferInfo)).isTrue();
assertBufferInfosEqual(bufferInfo, outBufferInfo);
}
@Test
@ -153,8 +152,7 @@ public class AsynchronousMediaCodecAdapterTest {
}
@Test
public void dequeueOutputBufferIndex_afterFlushCompletes_returnsNextOutputBuffer()
throws InterruptedException {
public void dequeueOutputBufferIndex_afterFlushCompletes_returnsNextOutputBuffer() {
adapter.start();
Handler handler = new Handler(looper);
MediaCodec.BufferInfo info0 = new MediaCodec.BufferInfo();
@ -166,14 +164,14 @@ public class AsynchronousMediaCodecAdapterTest {
handler.post(
() -> adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 1, info1));
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(1);
assertThat(areEqual(bufferInfo, info1)).isTrue();
assertBufferInfosEqual(info1, bufferInfo);
}
@Test
public void dequeueOutputBufferIndex_afterFlushCompletesWithError_throwsException()
throws InterruptedException {
public void dequeueOutputBufferIndex_afterFlushCompletesWithError_throwsException() {
AtomicInteger calls = new AtomicInteger(0);
adapter.setCodecStartRunnable(
() -> {
@ -184,7 +182,8 @@ public class AsynchronousMediaCodecAdapterTest {
adapter.start();
adapter.flush();
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
}
@ -213,26 +212,28 @@ public class AsynchronousMediaCodecAdapterTest {
}
@Test
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
public void getOutputFormat_afterFlush_returnsPreviousFormat() {
adapter.start();
MediaFormat format = new MediaFormat();
adapter.getMediaCodecCallback().onOutputFormatChanged(codec, format);
adapter.dequeueOutputBufferIndex(bufferInfo);
adapter.flush();
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.getOutputFormat()).isEqualTo(format);
}
@Test
public void shutdown_withPendingFlush_cancelsFlush() throws InterruptedException {
public void shutdown_withPendingFlush_cancelsFlush() {
AtomicInteger onCodecStartCalled = new AtomicInteger(0);
adapter.setCodecStartRunnable(() -> onCodecStartCalled.incrementAndGet());
adapter.start();
adapter.flush();
adapter.shutdown();
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(onCodecStartCalled.get()).isEqualTo(1);
}
}

View File

@ -16,8 +16,7 @@
package com.google.android.exoplayer2.mediacodec;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.robolectric.Shadows.shadowOf;
@ -29,13 +28,13 @@ import android.os.HandlerThread;
import android.os.Looper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowLooper;
/** Unit tests for {@link DedicatedThreadAsyncMediaCodecAdapter}. */
@ -44,7 +43,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
private DedicatedThreadAsyncMediaCodecAdapter adapter;
private MediaCodec codec;
private TestHandlerThread handlerThread;
private MediaCodec.BufferInfo bufferInfo = null;
private MediaCodec.BufferInfo bufferInfo;
@Before
public void setUp() throws IOException {
@ -69,8 +68,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
}
@Test
public void dequeueInputBufferIndex_withAfterFlushFailed_throwsException()
throws InterruptedException {
public void dequeueInputBufferIndex_withAfterFlushFailed_throwsException() {
AtomicInteger codecStartCalls = new AtomicInteger(0);
adapter.setCodecStartRunnable(
() -> {
@ -81,11 +79,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
adapter.start();
adapter.flush();
assertThat(
waitUntilAllEventsAreExecuted(
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
.isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
}
@ -114,8 +109,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
}
@Test
public void dequeueInputBufferIndex_withFlushCompletedAndInputBuffer_returnsInputBuffer()
throws InterruptedException {
public void dequeueInputBufferIndex_withFlushCompletedAndInputBuffer_returnsInputBuffer() {
adapter.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
@ -128,8 +122,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
// Enqueue another onInputBufferAvailable after the flush event
handler.post(() -> adapter.onInputBufferAvailable(codec, 10));
// Wait until all tasks have been handled
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(10);
}
@ -142,8 +136,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
}
@Test
public void dequeueOutputBufferIndex_withInternalException_throwsException()
throws InterruptedException {
public void dequeueOutputBufferIndex_withInternalException_throwsException() {
AtomicInteger codecStartCalls = new AtomicInteger(0);
adapter.setCodecStartRunnable(
() -> {
@ -154,10 +147,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
adapter.start();
adapter.flush();
assertThat(
waitUntilAllEventsAreExecuted(
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
.isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
}
@ -176,7 +167,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
adapter.onOutputBufferAvailable(codec, 0, enqueuedBufferInfo);
assertThat(adapter.dequeueOutputBufferIndex((bufferInfo))).isEqualTo(0);
assertThat(areEqual(bufferInfo, enqueuedBufferInfo)).isTrue();
assertBufferInfosEqual(enqueuedBufferInfo, bufferInfo);
}
@Test
@ -190,8 +181,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
}
@Test
public void dequeueOutputBufferIndex_withFlushCompletedAndOutputBuffer_returnsOutputBuffer()
throws InterruptedException {
public void dequeueOutputBufferIndex_withFlushCompletedAndOutputBuffer_returnsOutputBuffer() {
adapter.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
@ -208,10 +198,10 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
lastBufferInfo.presentationTimeUs = 10;
handler.post(() -> adapter.onOutputBufferAvailable(codec, 10, lastBufferInfo));
// Wait until all tasks have been handled
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(10);
assertThat(areEqual(bufferInfo, lastBufferInfo)).isTrue();
assertBufferInfosEqual(lastBufferInfo, bufferInfo);
}
@Test
@ -250,7 +240,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
}
@Test
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
public void getOutputFormat_afterFlush_returnsPreviousFormat() {
MediaFormat format = new MediaFormat();
adapter.start();
adapter.onOutputFormatChanged(codec, format);
@ -260,15 +250,14 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
assertThat(adapter.getOutputFormat()).isEqualTo(format);
adapter.flush();
assertThat(
waitUntilAllEventsAreExecuted(
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
.isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.getOutputFormat()).isEqualTo(format);
}
@Test
public void flush_multipleTimes_onlyLastFlushExecutes() throws InterruptedException {
public void flush_multipleTimes_onlyLastFlushExecutes() {
AtomicInteger codecStartCalls = new AtomicInteger(0);
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
adapter.start();
@ -290,22 +279,22 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
}
assertThat(codecStartCalls.get()).isEqualTo(1);
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
shadowLooper.idle();
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(3);
assertThat(codecStartCalls.get()).isEqualTo(2);
}
@Test
public void flush_andImmediatelyShutdown_flushIsNoOp() throws InterruptedException {
public void flush_andImmediatelyShutdown_flushIsNoOp() {
AtomicInteger onCodecStartCount = new AtomicInteger(0);
adapter.setCodecStartRunnable(() -> onCodecStartCount.incrementAndGet());
adapter.start();
// Obtain looper when adapter is started
Looper looper = handlerThread.getLooper();
adapter.flush();
adapter.shutdown();
assertThat(waitUntilAllEventsAreExecuted(looper, 5, TimeUnit.SECONDS)).isTrue();
// Wait until all tasks have been handled.
Shadows.shadowOf(handlerThread.getLooper()).idle();
// Only adapter.start() calls onCodecStart.
assertThat(onCodecStartCount.get()).isEqualTo(1);
}

View File

@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer2.mediacodec;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
@ -101,9 +101,9 @@ public class MediaCodecAsyncCallbackTest {
MediaCodec.BufferInfo outBufferInfo = new MediaCodec.BufferInfo();
assertThat(mediaCodecAsyncCallback.dequeueOutputBufferIndex(outBufferInfo)).isEqualTo(0);
assertThat(areEqual(outBufferInfo, bufferInfo1)).isTrue();
assertBufferInfosEqual(bufferInfo1, outBufferInfo);
assertThat(mediaCodecAsyncCallback.dequeueOutputBufferIndex(outBufferInfo)).isEqualTo(1);
assertThat(areEqual(outBufferInfo, bufferInfo2)).isTrue();
assertBufferInfosEqual(bufferInfo2, outBufferInfo);
assertThat(mediaCodecAsyncCallback.dequeueOutputBufferIndex(outBufferInfo))
.isEqualTo(MediaCodec.INFO_TRY_AGAIN_LATER);
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2019 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.mediacodec;
import static org.robolectric.Shadows.shadowOf;
import android.media.MediaCodec;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** Testing utilities for MediaCodec related test classes */
public class MediaCodecTestUtils {
/**
* Compares if two {@link android.media.MediaCodec.BufferInfo} are equal by inspecting {@link
* android.media.MediaCodec.BufferInfo#flags}, {@link android.media.MediaCodec.BufferInfo#size},
* {@link android.media.MediaCodec.BufferInfo#presentationTimeUs} and {@link
* android.media.MediaCodec.BufferInfo#offset}.
*/
public static boolean areEqual(MediaCodec.BufferInfo lhs, MediaCodec.BufferInfo rhs) {
return lhs.flags == rhs.flags
&& lhs.offset == rhs.offset
&& lhs.presentationTimeUs == rhs.presentationTimeUs
&& lhs.size == rhs.size;
}
/**
* Blocks until all events of a shadow looper are executed or the specified time elapses.
*
* @param looper the shadow looper
* @param time the time to wait
* @param unit the time units
* @return true if all events are executed, false if the time elapsed.
* @throws InterruptedException if the Thread was interrupted while waiting.
*/
public static boolean waitUntilAllEventsAreExecuted(Looper looper, long time, TimeUnit unit)
throws InterruptedException {
Handler handler = new Handler(looper);
CountDownLatch latch = new CountDownLatch(1);
handler.post(() -> latch.countDown());
shadowOf(looper).idle();
return latch.await(time, unit);
}
}

View File

@ -16,8 +16,7 @@
package com.google.android.exoplayer2.mediacodec;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
import static com.google.android.exoplayer2.testutil.TestUtil.assertBufferInfosEqual;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.robolectric.Shadows.shadowOf;
@ -29,13 +28,13 @@ import android.os.HandlerThread;
import android.os.Looper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowLooper;
/** Unit tests for {@link MultiLockAsyncMediaCodecAdapter}. */
@ -43,7 +42,7 @@ import org.robolectric.shadows.ShadowLooper;
public class MultiLockAsyncMediaCodecAdapterTest {
private MultiLockAsyncMediaCodecAdapter adapter;
private MediaCodec codec;
private MediaCodec.BufferInfo bufferInfo = null;
private MediaCodec.BufferInfo bufferInfo;
private TestHandlerThread handlerThread;
@Before
@ -81,10 +80,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
adapter.start();
adapter.flush();
assertThat(
waitUntilAllEventsAreExecuted(
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
.isTrue();
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
}
@ -128,7 +124,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
handler.post(() -> adapter.onInputBufferAvailable(codec, 10));
// Wait until all tasks have been handled
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(10);
}
@ -154,10 +150,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
adapter.start();
adapter.flush();
assertThat(
waitUntilAllEventsAreExecuted(
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
.isTrue();
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
}
@ -176,7 +169,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
adapter.onOutputBufferAvailable(codec, 0, enqueuedBufferInfo);
assertThat(adapter.dequeueOutputBufferIndex((bufferInfo))).isEqualTo(0);
assertThat(areEqual(bufferInfo, enqueuedBufferInfo)).isTrue();
assertBufferInfosEqual(enqueuedBufferInfo, bufferInfo);
}
@Test
@ -209,9 +202,9 @@ public class MultiLockAsyncMediaCodecAdapterTest {
handler.post(() -> adapter.onOutputBufferAvailable(codec, 10, lastBufferInfo));
// Wait until all tasks have been handled
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo)).isEqualTo(10);
assertThat(areEqual(bufferInfo, lastBufferInfo)).isTrue();
assertBufferInfosEqual(lastBufferInfo, bufferInfo);
}
@Test
@ -250,7 +243,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
}
@Test
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
public void getOutputFormat_afterFlush_returnsPreviousFormat() {
MediaFormat format = new MediaFormat();
adapter.start();
adapter.onOutputFormatChanged(codec, format);
@ -260,15 +253,12 @@ public class MultiLockAsyncMediaCodecAdapterTest {
assertThat(adapter.getOutputFormat()).isEqualTo(format);
adapter.flush();
assertThat(
waitUntilAllEventsAreExecuted(
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
.isTrue();
Shadows.shadowOf(handlerThread.getLooper()).idle();
assertThat(adapter.getOutputFormat()).isEqualTo(format);
}
@Test
public void flush_multipleTimes_onlyLastFlushExecutes() throws InterruptedException {
public void flush_multipleTimes_onlyLastFlushExecutes() {
AtomicInteger codecStartCalls = new AtomicInteger(0);
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
adapter.start();
@ -290,22 +280,20 @@ public class MultiLockAsyncMediaCodecAdapterTest {
}
assertThat(codecStartCalls.get()).isEqualTo(1);
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
shadowLooper.idle();
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(3);
assertThat(codecStartCalls.get()).isEqualTo(2);
}
@Test
public void flush_andImmediatelyShutdown_flushIsNoOp() throws InterruptedException {
public void flush_andImmediatelyShutdown_flushIsNoOp() {
AtomicInteger codecStartCalls = new AtomicInteger(0);
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
adapter.start();
// Obtain looper when adapter is started.
Looper looper = handlerThread.getLooper();
adapter.flush();
adapter.shutdown();
assertThat(waitUntilAllEventsAreExecuted(looper, 5, TimeUnit.SECONDS)).isTrue();
Shadows.shadowOf(handlerThread.getLooper()).idle();
// Only adapter.start() called codec#start()
assertThat(codecStartCalls.get()).isEqualTo(1);
}

View File

@ -23,6 +23,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.database.DatabaseIOException;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.database.VersionTable;
import com.google.android.exoplayer2.testutil.DownloadBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

View File

@ -24,6 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.Download.State;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.DownloadBuilder;
import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;

View File

@ -22,6 +22,7 @@ import static org.junit.Assert.fail;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import org.junit.Before;
@ -45,7 +46,7 @@ public final class DataSchemeDataSourceTest {
@Test
public void testBase64Data() throws IOException {
DataSpec dataSpec = buildDataSpec(DATA_SCHEME_URI);
DataSourceAsserts.assertDataSourceContent(
assertDataSourceContent(
schemeDataDataSource,
dataSpec,
Util.getUtf8Bytes(
@ -55,7 +56,7 @@ public final class DataSchemeDataSourceTest {
@Test
public void testAsciiData() throws IOException {
DataSourceAsserts.assertDataSourceContent(
assertDataSourceContent(
schemeDataDataSource,
buildDataSpec("data:,A%20brief%20note"),
Util.getUtf8Bytes("A brief note"));
@ -78,22 +79,21 @@ public final class DataSchemeDataSourceTest {
public void testSequentialRangeRequests() throws IOException {
DataSpec dataSpec =
buildDataSpec(DATA_SCHEME_URI, /* position= */ 1, /* length= */ C.LENGTH_UNSET);
DataSourceAsserts.assertDataSourceContent(
assertDataSourceContent(
schemeDataDataSource,
dataSpec,
Util.getUtf8Bytes(
"\"provider\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
+ "[\"00000000000000000000000000000000\"]}"));
dataSpec = buildDataSpec(DATA_SCHEME_URI, /* position= */ 10, /* length= */ C.LENGTH_UNSET);
DataSourceAsserts.assertDataSourceContent(
assertDataSourceContent(
schemeDataDataSource,
dataSpec,
Util.getUtf8Bytes(
"\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
+ "[\"00000000000000000000000000000000\"]}"));
dataSpec = buildDataSpec(DATA_SCHEME_URI, /* position= */ 15, /* length= */ 5);
DataSourceAsserts.assertDataSourceContent(
schemeDataDataSource, dataSpec, Util.getUtf8Bytes("devin"));
assertDataSourceContent(schemeDataDataSource, dataSpec, Util.getUtf8Bytes("devin"));
}
@Test
@ -154,4 +154,23 @@ public final class DataSchemeDataSourceTest {
return new DataSpec(Uri.parse(uriString), position, length, /* key= */ null);
}
/**
* Asserts that data read from a {@link DataSource} matches {@code expected}.
*
* @param dataSource The {@link DataSource} through which to read.
* @param dataSpec The {@link DataSpec} to use when opening the {@link DataSource}.
* @param expectedData The expected data.
* @throws IOException If an error occurs reading fom the {@link DataSource}.
*/
private static void assertDataSourceContent(
DataSource dataSource, DataSpec dataSpec, byte[] expectedData) throws IOException {
try {
long length = dataSource.open(dataSpec);
assertThat(length).isEqualTo(expectedData.length);
byte[] readData = TestUtil.readToEnd(dataSource);
assertThat(readData).isEqualTo(expectedData);
} finally {
dataSource.close();
}
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.upstream;
import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException;
/**
* Assertions for data source tests.
*/
/* package */ final class DataSourceAsserts {
/**
* Asserts that data read from a {@link DataSource} matches {@code expected}.
*
* @param dataSource The {@link DataSource} through which to read.
* @param dataSpec The {@link DataSpec} to use when opening the {@link DataSource}.
* @param expectedData The expected data.
* @throws IOException If an error occurs reading fom the {@link DataSource}.
*/
public static void assertDataSourceContent(DataSource dataSource, DataSpec dataSpec,
byte[] expectedData) throws IOException {
try {
long length = dataSource.open(dataSpec);
assertThat(length).isEqualTo(expectedData.length);
byte[] readData = TestUtil.readToEnd(dataSource);
assertThat(readData).isEqualTo(expectedData);
} finally {
dataSource.close();
}
}
private DataSourceAsserts() {}
}

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream.cache;
import static com.google.android.exoplayer2.testutil.TestUtil.createTestFile;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@ -103,12 +104,9 @@ public class CachedContentIndexTest {
// add a span
int cacheFileLength = 20;
File cacheSpanFile =
SimpleCacheSpanTest.createCacheSpanFile(
cacheDir,
cachedContent1.id,
/* offset= */ 10,
cacheFileLength,
/* lastTouchTimestamp= */ 30);
SimpleCacheSpan.getCacheFile(
cacheDir, cachedContent1.id, /* position= */ 10, /* timestamp= */ 30);
createTestFile(cacheSpanFile, cacheFileLength);
SimpleCacheSpan span = SimpleCacheSpan.createCacheEntry(cacheSpanFile, cacheFileLength, index);
assertThat(span).isNotNull();
cachedContent1.addSpan(span);
@ -288,12 +286,9 @@ public class CachedContentIndexTest {
CachedContent cachedContent = index.getOrAdd("key1");
long cacheFileLength = 20;
File cacheFile =
SimpleCacheSpanTest.createCacheSpanFile(
cacheDir,
cachedContent.id,
/* offset= */ 10,
cacheFileLength,
/* lastTouchTimestamp= */ 30);
SimpleCacheSpan.getCacheFile(
cacheDir, cachedContent.id, /* position= */ 10, /* timestamp= */ 30);
createTestFile(cacheFile, cacheFileLength);
SimpleCacheSpan span = SimpleCacheSpan.createCacheEntry(cacheFile, cacheFileLength, index);
cachedContent.addSpan(span);

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.upstream.cache;
import static com.google.android.exoplayer2.testutil.TestUtil.createTestFile;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@ -24,7 +25,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
@ -37,13 +37,6 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SimpleCacheSpanTest {
public static File createCacheSpanFile(
File cacheDir, int id, long offset, long length, long lastTouchTimestamp) throws IOException {
File cacheFile = SimpleCacheSpan.getCacheFile(cacheDir, id, offset, lastTouchTimestamp);
createTestFile(cacheFile, length);
return cacheFile;
}
private CachedContentIndex index;
private File cacheDir;
@ -82,10 +75,10 @@ public class SimpleCacheSpanTest {
public void testUpgradeFileName() throws Exception {
String key = "abc%def";
int id = index.assignIdForKey(key);
File v3file = createTestFile(id + ".0.1.v3.exo");
File v2file = createTestFile("abc%25def.1.2.v2.exo"); // %25 is '%' after escaping
File wrongEscapedV2file = createTestFile("abc%2Gdef.3.4.v2.exo"); // 2G is invalid hex
File v1File = createTestFile("abc%def.5.6.v1.exo"); // V1 did not escape
File v3file = createTestFile(cacheDir, id + ".0.1.v3.exo");
File v2file = createTestFile(cacheDir, "abc%25def.1.2.v2.exo"); // %25 is '%' after escaping
File wrongEscapedV2file = createTestFile(cacheDir, "abc%2Gdef.3.4.v2.exo"); // 2G is invalid hex
File v1File = createTestFile(cacheDir, "abc%def.5.6.v1.exo"); // V1 did not escape
for (File file : cacheDir.listFiles()) {
SimpleCacheSpan cacheEntry = SimpleCacheSpan.createCacheEntry(file, file.length(), index);
@ -125,26 +118,12 @@ public class SimpleCacheSpanTest {
assertThat(cachedPositions.get(5)).isEqualTo(6);
}
private static void createTestFile(File file, long length) throws IOException {
FileOutputStream output = new FileOutputStream(file);
for (int i = 0; i < length; i++) {
output.write(i);
}
output.close();
}
private File createTestFile(String name) throws IOException {
File file = new File(cacheDir, name);
createTestFile(file, 1);
return file;
}
private void assertCacheSpan(String key, long offset, long lastTouchTimestamp)
throws IOException {
int id = index.assignIdForKey(key);
long cacheFileLength = 1;
File cacheFile = createCacheSpanFile(cacheDir, id, offset, cacheFileLength, lastTouchTimestamp);
SimpleCacheSpan cacheSpan = SimpleCacheSpan.createCacheEntry(cacheFile, cacheFileLength, index);
File cacheFile = SimpleCacheSpan.getCacheFile(cacheDir, id, offset, lastTouchTimestamp);
createTestFile(cacheFile, /* length= */ 1);
SimpleCacheSpan cacheSpan = SimpleCacheSpan.createCacheEntry(cacheFile, /* length= */ 1, index);
String message = cacheFile.toString();
assertWithMessage(message).that(cacheSpan).isNotNull();
assertWithMessage(message).that(cacheFile.getParentFile()).isEqualTo(cacheDir);

View File

@ -13,11 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.offline;
package com.google.android.exoplayer2.testutil;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.Download;
import com.google.android.exoplayer2.offline.DownloadProgress;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.StreamKey;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -29,7 +33,7 @@ import java.util.List;
* creation for tests. Tests must avoid depending on the default values but explicitly set tested
* parameters during test initialization.
*/
/* package */ final class DownloadBuilder {
public final class DownloadBuilder {
private final DownloadProgress progress;
@ -47,7 +51,12 @@ import java.util.List;
private int stopReason;
private int failureReason;
/* package */ DownloadBuilder(String id) {
/**
* Creates a download builder for "uri" with type "type" and no stream keys.
*
* @param id The unique content identifier for the download.
*/
public DownloadBuilder(String id) {
this(
id,
"type",
@ -57,7 +66,12 @@ import java.util.List;
new byte[0]);
}
/* package */ DownloadBuilder(DownloadRequest request) {
/**
* Creates a download builder based on the attributes of the specified request.
*
* @param request A {@link DownloadRequest} defining the content to download.
*/
public DownloadBuilder(DownloadRequest request) {
this(
request.id,
request.type,
@ -67,12 +81,13 @@ import java.util.List;
request.data);
}
/* package */ DownloadBuilder(
/** Creates a download builder. */
private DownloadBuilder(
String id,
String type,
Uri uri,
List<StreamKey> streamKeys,
String cacheKey,
@Nullable String cacheKey,
byte[] customMetadata) {
this.id = id;
this.type = type;
@ -86,76 +101,85 @@ import java.util.List;
this.progress = new DownloadProgress();
}
public DownloadBuilder setId(String id) {
this.id = id;
return this;
}
/** @see DownloadRequest#type */
public DownloadBuilder setType(String type) {
this.type = type;
return this;
}
/** @see DownloadRequest#uri */
public DownloadBuilder setUri(String uri) {
this.uri = Uri.parse(uri);
return this;
}
/** @see DownloadRequest#uri */
public DownloadBuilder setUri(Uri uri) {
this.uri = uri;
return this;
}
/** @see DownloadRequest#customCacheKey */
public DownloadBuilder setCacheKey(@Nullable String cacheKey) {
this.cacheKey = cacheKey;
return this;
}
/** @see Download#state */
public DownloadBuilder setState(@Download.State int state) {
this.state = state;
return this;
}
/** @see DownloadProgress#percentDownloaded */
public DownloadBuilder setPercentDownloaded(float percentDownloaded) {
progress.percentDownloaded = percentDownloaded;
return this;
}
/** @see DownloadProgress#bytesDownloaded */
public DownloadBuilder setBytesDownloaded(long bytesDownloaded) {
progress.bytesDownloaded = bytesDownloaded;
return this;
}
/** @see Download#contentLength */
public DownloadBuilder setContentLength(long contentLength) {
this.contentLength = contentLength;
return this;
}
/** @see Download#failureReason */
public DownloadBuilder setFailureReason(int failureReason) {
this.failureReason = failureReason;
return this;
}
/** @see Download#stopReason */
public DownloadBuilder setStopReason(int stopReason) {
this.stopReason = stopReason;
return this;
}
/** @see Download#startTimeMs */
public DownloadBuilder setStartTimeMs(long startTimeMs) {
this.startTimeMs = startTimeMs;
return this;
}
/** @see Download#updateTimeMs */
public DownloadBuilder setUpdateTimeMs(long updateTimeMs) {
this.updateTimeMs = updateTimeMs;
return this;
}
/** @see DownloadRequest#streamKeys */
public DownloadBuilder setStreamKeys(StreamKey... streamKeys) {
this.streamKeys = Arrays.asList(streamKeys);
return this;
}
/** @see DownloadRequest#data */
public DownloadBuilder setCustomMetadata(byte[] customMetadata) {
this.customMetadata = customMetadata;
return this;

View File

@ -24,6 +24,7 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.MediaCodec;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.database.DatabaseProvider;
@ -37,6 +38,8 @@ import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@ -180,6 +183,26 @@ public class TestUtil {
return joined;
}
/** Writes one byte long dummy test data to the file and returns it. */
public static File createTestFile(File directory, String name) throws IOException {
return createTestFile(directory, name, /* length= */ 1);
}
/** Writes dummy test data with the specified length to the file and returns it. */
public static File createTestFile(File directory, String name, long length) throws IOException {
return createTestFile(new File(directory, name), length);
}
/** Writes dummy test data with the specified length to the file and returns it. */
public static File createTestFile(File file, long length) throws IOException {
FileOutputStream output = new FileOutputStream(file);
for (long i = 0; i < length; i++) {
output.write((int) i);
}
output.close();
return file;
}
/** Returns the bytes of an asset file. */
public static byte[] getByteArray(Context context, String fileName) throws IOException {
return Util.toByteArray(getInputStream(context, fileName));
@ -240,6 +263,15 @@ public class TestUtil {
}
}
/** Returns whether two {@link android.media.MediaCodec.BufferInfo BufferInfos} are equal. */
public static void assertBufferInfosEqual(
MediaCodec.BufferInfo expected, MediaCodec.BufferInfo actual) {
assertThat(expected.flags).isEqualTo(actual.flags);
assertThat(expected.offset).isEqualTo(actual.offset);
assertThat(expected.presentationTimeUs).isEqualTo(actual.presentationTimeUs);
assertThat(expected.size).isEqualTo(actual.size);
}
/**
* Asserts whether actual bitmap is very similar to the expected bitmap at some quality level.
*