diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/ForwardingExtractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/ForwardingExtractor.java index 0d57712fa9..b8816cec06 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/ForwardingExtractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/ForwardingExtractor.java @@ -17,6 +17,7 @@ package androidx.media3.extractor; import androidx.media3.common.util.UnstableApi; import java.io.IOException; +import java.util.List; /** * An overridable {@link Extractor} implementation forwarding all methods to an underlying @@ -35,6 +36,11 @@ public class ForwardingExtractor implements Extractor { return delegate.sniff(input); } + @Override + public List getSniffFailureDetails() { + return delegate.getSniffFailureDetails(); + } + @Override public void init(ExtractorOutput output) { delegate.init(output); @@ -55,4 +61,9 @@ public class ForwardingExtractor implements Extractor { public void release() { delegate.release(); } + + @Override + public Extractor getUnderlyingImplementation() { + return delegate.getUnderlyingImplementation(); + } } diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/ForwardingExtractorOutputTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/ForwardingExtractorOutputTest.java new file mode 100644 index 0000000000..34bce79e8c --- /dev/null +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/ForwardingExtractorOutputTest.java @@ -0,0 +1,23 @@ +package androidx.media3.extractor; + +import static androidx.media3.test.utils.TestUtil.assertForwardingClassForwardsAllMethods; +import static androidx.media3.test.utils.TestUtil.assertForwardingClassOverridesAllMethods; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class ForwardingExtractorOutputTest { + + @Test + public void overridesAllMethods() throws Exception { + assertForwardingClassOverridesAllMethods( + ExtractorOutput.class, ForwardingExtractorOutput.class); + } + + @Test + public void forwardsAllMethods() throws Exception { + assertForwardingClassForwardsAllMethods(ExtractorOutput.class, ForwardingExtractorOutput::new); + } +} diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/ForwardingExtractorTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/ForwardingExtractorTest.java new file mode 100644 index 0000000000..38546bdc59 --- /dev/null +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/ForwardingExtractorTest.java @@ -0,0 +1,22 @@ +package androidx.media3.extractor; + +import static androidx.media3.test.utils.TestUtil.assertForwardingClassForwardsAllMethods; +import static androidx.media3.test.utils.TestUtil.assertForwardingClassOverridesAllMethods; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class ForwardingExtractorTest { + + @Test + public void overridesAllMethods() throws Exception { + assertForwardingClassOverridesAllMethods(Extractor.class, ForwardingExtractor.class); + } + + @Test + public void forwardsAllMethods() throws Exception { + assertForwardingClassForwardsAllMethods(Extractor.class, ForwardingExtractor::new); + } +} diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java index 9608b662bd..3e5a49ff30 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java @@ -18,6 +18,8 @@ package androidx.media3.test.utils; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import android.content.Context; import android.database.sqlite.SQLiteDatabase; @@ -36,6 +38,7 @@ import androidx.media3.common.MediaMetadata; import androidx.media3.common.StreamKey; import androidx.media3.common.Timeline; import androidx.media3.common.TrackGroup; +import androidx.media3.common.util.NullableType; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.database.DatabaseProvider; @@ -51,6 +54,7 @@ import androidx.media3.extractor.ExtractorInput; import androidx.media3.extractor.PositionHolder; import androidx.media3.extractor.SeekMap; import androidx.media3.extractor.metadata.MetadataInputBuffer; +import com.google.common.base.Function; import com.google.common.collect.BoundType; import com.google.common.collect.ImmutableList; import com.google.common.collect.Range; @@ -63,6 +67,8 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.ByteBuffer; @@ -618,6 +624,42 @@ public class TestUtil { return list; } + /** + * Use reflection to assert that every method declared on {@code superType} is overridden by + * {@code forwardingType}. + */ + public static void assertForwardingClassOverridesAllMethods( + Class superType, Class forwardingType) throws NoSuchMethodException { + for (Method method : TestUtil.getPublicMethods(superType)) { + assertThat( + forwardingType + .getDeclaredMethod(method.getName(), method.getParameterTypes()) + .getDeclaringClass()) + .isEqualTo(forwardingType); + } + } + + /** + * Use reflection to assert calling every method declared on {@code superType} on an instance of + * {@code forwardingType} results in the call being forwarded to the {@code superType} delegate. + */ + public static void assertForwardingClassForwardsAllMethods( + Class superType, Function forwardingInstanceFactory) + throws InvocationTargetException, IllegalAccessException { + for (Method method : getPublicMethods(superType)) { + T delegate = mock(superType); + F forwardingInstance = forwardingInstanceFactory.apply(delegate); + @NullableType Object[] parameters = new Object[method.getParameterCount()]; + for (int i = 0; i < method.getParameterCount(); i++) { + // Get a default value of the right type by creating a single-element array. This gives us + // null for object types, and the 'default' value for primitives. + parameters[i] = Array.get(Array.newInstance(method.getParameterTypes()[i], 1), 0); + } + method.invoke(forwardingInstance, parameters); + method.invoke(verify(delegate), parameters); + } + } + /** Returns a {@link MediaItem} that has all fields set to non-default values. */ public static MediaItem buildFullyCustomizedMediaItem() { return new MediaItem.Builder()