From ded68ed981de44444284bf6c134a1eb786443afe Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 10 Nov 2021 12:01:41 +0000 Subject: [PATCH] Add contract tests for DataSource#getResponseHeaders PiperOrigin-RevId: 408840409 --- .../DefaultHttpDataSourceContractTest.java | 5 ++ .../test/utils/DataSourceContractTest.java | 81 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/libraries/datasource/src/androidTest/java/androidx/media3/datasource/DefaultHttpDataSourceContractTest.java b/libraries/datasource/src/androidTest/java/androidx/media3/datasource/DefaultHttpDataSourceContractTest.java index 7c9e750538..c9059fba42 100644 --- a/libraries/datasource/src/androidTest/java/androidx/media3/datasource/DefaultHttpDataSourceContractTest.java +++ b/libraries/datasource/src/androidTest/java/androidx/media3/datasource/DefaultHttpDataSourceContractTest.java @@ -20,6 +20,7 @@ import androidx.media3.test.utils.DataSourceContractTest; import androidx.media3.test.utils.HttpDataSourceTestEnv; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; +import org.junit.Ignore; import org.junit.Rule; import org.junit.runner.RunWith; @@ -43,4 +44,8 @@ public class DefaultHttpDataSourceContractTest extends DataSourceContractTest { protected Uri getNotFoundUri() { return Uri.parse(httpDataSourceTestEnv.getNonexistentUrl()); } + + @Override + @Ignore("internal b/205811776") + public void getResponseHeaders_noNullKeysOrValues() {} } 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 d87240cb77..0de48ee467 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 @@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Util.castNonNull; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -40,10 +41,12 @@ import androidx.media3.datasource.DataSourceException; import androidx.media3.datasource.DataSourceUtil; import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.TransferListener; +import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.Map; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.junit.Ignore; import org.junit.Rule; @@ -505,6 +508,62 @@ public abstract class DataSourceContractTest { assertThat(dataSource.getUri()).isNull(); } + @Test + public void getResponseHeaders_noNullKeysOrValues() throws Exception { + ImmutableList resources = getTestResources(); + Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource."); + + for (int i = 0; i < resources.size(); i++) { + additionalFailureInfo.setInfo(getFailureLabel(resources, i)); + TestResource resource = resources.get(i); + DataSource dataSource = createDataSource(); + try { + dataSource.open(new DataSpec(resource.getUri())); + + Map> responseHeaders = dataSource.getResponseHeaders(); + assertThat(responseHeaders).doesNotContainKey(null); + assertThat(responseHeaders.values()).doesNotContain(null); + for (List value : responseHeaders.values()) { + assertThat(value).doesNotContain(null); + } + } finally { + dataSource.close(); + } + additionalFailureInfo.setInfo(null); + } + } + + @Test + public void getResponseHeaders_caseInsensitive() throws Exception { + ImmutableList resources = getTestResources(); + Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource."); + + for (int i = 0; i < resources.size(); i++) { + additionalFailureInfo.setInfo(getFailureLabel(resources, i)); + TestResource resource = resources.get(i); + DataSource dataSource = createDataSource(); + try { + dataSource.open(new DataSpec(resource.getUri())); + + Map> responseHeaders = dataSource.getResponseHeaders(); + for (String key : responseHeaders.keySet()) { + // TODO(internal b/205811776): Remove this when DefaultHttpDataSource is fixed to not + // return a null key. + if (key == null) { + continue; + } + String caseFlippedKey = invertAsciiCaseOfEveryOtherCharacter(key); + assertWithMessage("key='%s', caseFlippedKey='%s'", key, caseFlippedKey) + .that(responseHeaders.get(caseFlippedKey)) + .isEqualTo(responseHeaders.get(key)); + } + } finally { + dataSource.close(); + } + additionalFailureInfo.setInfo(null); + } + } + @Test public void getResponseHeaders_isEmptyWhileNotOpen() throws Exception { ImmutableList resources = getTestResources(); @@ -550,6 +609,28 @@ public abstract class DataSourceContractTest { } } + private static String invertAsciiCaseOfEveryOtherCharacter(String input) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + result.append(i % 2 == 0 ? invertAsciiCase(input.charAt(i)) : input.charAt(i)); + } + return result.toString(); + } + + /** + * Returns {@code c} in the opposite case if it's an ASCII character, otherwise returns {@code c} + * unchanged. + */ + private static char invertAsciiCase(char c) { + if (Ascii.isUpperCase(c)) { + return Ascii.toLowerCase(c); + } else if (Ascii.isLowerCase(c)) { + return Ascii.toUpperCase(c); + } else { + return c; + } + } + /** Information about a resource that can be used to test the {@link DataSource} instance. */ public static final class TestResource {