diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1287385418..9c5142fc06 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -95,6 +95,9 @@ * Leanback extension: * Cast Extension: * Test Utilities: + * `DataSourceContractTest` now includes tests to verify: + * Input stream `read position` is updated. + * Output buffer `offset` is applied correctly. * Demo app: * Remove deprecated symbols: * Remove deprecated `Player.hasPrevious`, `Player.hasPreviousWindow()`. diff --git a/libraries/datasource/src/test/java/androidx/media3/datasource/UdpDataSourceContractTest.java b/libraries/datasource/src/test/java/androidx/media3/datasource/UdpDataSourceContractTest.java index 1d426cf1a5..e2349f57e6 100644 --- a/libraries/datasource/src/test/java/androidx/media3/datasource/UdpDataSourceContractTest.java +++ b/libraries/datasource/src/test/java/androidx/media3/datasource/UdpDataSourceContractTest.java @@ -83,6 +83,11 @@ public class UdpDataSourceContractTest extends DataSourceContractTest { @Override public void dataSpecWithLength_readExpectedRange() {} + @Test + @Ignore("UdpDataSource doesn't support DataSpec's position or length [internal: b/175856954]") + @Override + public void dataSpecWithLength_readUntilEndInTwoParts() {} + @Test @Ignore("UdpDataSource doesn't support DataSpec's position or length [internal: b/175856954]") @Override diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/DataSourceContractTest.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/DataSourceContractTest.java index b43a8ff00a..c770220bc7 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/DataSourceContractTest.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/DataSourceContractTest.java @@ -151,6 +151,41 @@ public abstract class DataSourceContractTest { }); } + @Test + public void unboundedDataSpec_readExpectedBytesWithOffset() throws Exception { + forAllTestResourcesAndDataSources( + (resource, dataSource) -> { + try { + dataSource.open(new DataSpec.Builder().setUri(resource.getUri()).build()); + int offset = 2; + byte[] data = new byte[resource.getExpectedBytes().length + offset]; + // Initialize the first two bytes with non-zero values. + data[0] = (byte) 0xA5; + data[1] = (byte) 0x5A; + + while (offset != data.length) { + int bytesRead = dataSource.read(data, offset, resource.getExpectedBytes().length); + + if (bytesRead == C.RESULT_END_OF_INPUT) { + break; + } + + offset += bytesRead; + } + + // Assert that the first two bytes have not been modified. + assertThat(data[0]).isEqualTo((byte) 0xA5); + assertThat(data[1]).isEqualTo((byte) 0x5A); + + assertThat(offset).isEqualTo(data.length); + byte[] actualData = Arrays.copyOfRange(data, 2, data.length); + assertThat(actualData).isEqualTo(resource.getExpectedBytes()); + } finally { + dataSource.close(); + } + }); + } + @Test public void dataSpecWithPosition_readUntilEnd() throws Exception { forAllTestResourcesAndDataSources( @@ -196,6 +231,29 @@ public abstract class DataSourceContractTest { }); } + @Test + public void dataSpecWithLength_readUntilEndInTwoParts() throws Exception { + forAllTestResourcesAndDataSources( + (resource, dataSource) -> { + try { + int length = resource.getExpectedBytes().length; + dataSource.open( + new DataSpec.Builder().setUri(resource.getUri()).setLength(length).build()); + + byte[] firstPartData = DataSourceUtil.readExactly(dataSource, length / 2); + byte[] secondPartData = DataSourceUtil.readToEnd(dataSource); + + byte[] expectedFirstPartData = Arrays.copyOf(resource.getExpectedBytes(), length / 2); + byte[] expectedSecondPartData = + Arrays.copyOfRange(resource.getExpectedBytes(), length / 2, length); + assertThat(firstPartData).isEqualTo(expectedFirstPartData); + assertThat(secondPartData).isEqualTo(expectedSecondPartData); + } finally { + dataSource.close(); + } + }); + } + @Test public void dataSpecWithPositionAndLength_readExpectedRange() throws Exception { forAllTestResourcesAndDataSources(