Standardize ForwardingXXX tests

Add missing ones for `ForwardingExtractorInput` and `ForwardingSeekMap`.
`ForwardingTimeline` is a bit more fiddly, so it's left for a follow-up
change.

PiperOrigin-RevId: 701988492
This commit is contained in:
ibaker 2024-12-02 09:09:43 -08:00 committed by Copybara-Service
parent b2ba5da09b
commit 25c927e9f3
7 changed files with 136 additions and 65 deletions

View File

@ -18,17 +18,17 @@ package androidx.media3.common;
import static androidx.media3.common.Player.EVENT_IS_PLAYING_CHANGED; import static androidx.media3.common.Player.EVENT_IS_PLAYING_CHANGED;
import static androidx.media3.common.Player.EVENT_MEDIA_ITEM_TRANSITION; import static androidx.media3.common.Player.EVENT_MEDIA_ITEM_TRANSITION;
import static androidx.media3.common.Player.EVENT_TIMELINE_CHANGED; import static androidx.media3.common.Player.EVENT_TIMELINE_CHANGED;
import static androidx.media3.test.utils.TestUtil.assertForwardingClassForwardsAllMethodsExcept;
import static androidx.media3.test.utils.TestUtil.assertForwardingClassOverridesAllMethods;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.same; import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import androidx.media3.test.utils.StubPlayer; import androidx.media3.test.utils.StubPlayer;
import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.lang.reflect.Method; import com.google.common.collect.ImmutableSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -99,29 +99,27 @@ public class ForwardingPlayerTest {
@Test @Test
public void forwardingPlayer_overridesAllPlayerMethods() throws Exception { public void forwardingPlayer_overridesAllPlayerMethods() throws Exception {
// Check with reflection that ForwardingPlayer overrides all Player methods. assertForwardingClassOverridesAllMethods(Player.class, ForwardingPlayer.class);
List<Method> methods = TestUtil.getPublicMethods(Player.class);
for (Method method : methods) {
assertThat(
ForwardingPlayer.class
.getDeclaredMethod(method.getName(), method.getParameterTypes())
.getDeclaringClass())
.isEqualTo(ForwardingPlayer.class);
}
} }
@Test @Test
public void forwardingPlayer_forwardsAllPlayerMethods() throws Exception {
// addListener and removeListener don't directly forward their parameters due to wrapping in
// ForwardingListener. They are tested separately in addListener_addsForwardingListener() and
// removeListener_removesForwardingListener().
assertForwardingClassForwardsAllMethodsExcept(
Player.class,
ForwardingPlayer::new,
/* excludedMethods= */ ImmutableSet.of("addListener", "removeListener"));
}
@Test
@SuppressWarnings("unchecked")
public void forwardingListener_overridesAllListenerMethods() throws Exception { public void forwardingListener_overridesAllListenerMethods() throws Exception {
// Check with reflection that ForwardingListener overrides all Listener methods. // Check with reflection that ForwardingListener overrides all Listener methods.
Class<?> forwardingListenerClass = getInnerClass("ForwardingListener"); Class<? extends Player.Listener> forwardingListenerClass =
List<Method> methods = TestUtil.getPublicMethods(Player.Listener.class); (Class<? extends Player.Listener>) getInnerClass("ForwardingListener");
for (Method method : methods) { assertForwardingClassOverridesAllMethods(Player.Listener.class, forwardingListenerClass);
assertThat(
forwardingListenerClass
.getMethod(method.getName(), method.getParameterTypes())
.getDeclaringClass())
.isEqualTo(forwardingListenerClass);
}
} }
private static Class<?> getInnerClass(String className) { private static Class<?> getInnerClass(String className) {

View File

@ -15,12 +15,8 @@
*/ */
package androidx.media3.exoplayer; package androidx.media3.exoplayer;
import static com.google.common.truth.Truth.assertThat;
import androidx.media3.test.utils.TestUtil; import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -28,15 +24,12 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ForwardingRendererTest { public class ForwardingRendererTest {
@Test @Test
public void forwardingRenderer_overridesAllMethods() throws NoSuchMethodException { public void overridesAllMethods() throws NoSuchMethodException {
// Check with reflection that ForwardingRenderer overrides all Renderer methods. TestUtil.assertForwardingClassOverridesAllMethods(Renderer.class, ForwardingRenderer.class);
List<Method> methods = TestUtil.getPublicMethods(Renderer.class); }
for (Method method : methods) {
assertThat( @Test
ForwardingRenderer.class public void forwardsAllMethods() throws Exception {
.getDeclaredMethod(method.getName(), method.getParameterTypes()) TestUtil.assertForwardingClassForwardsAllMethods(Renderer.class, ForwardingRenderer::new);
.getDeclaringClass())
.isEqualTo(ForwardingRenderer.class);
}
} }
} }

View File

@ -15,12 +15,10 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static com.google.common.truth.Truth.assertThat; import static androidx.media3.test.utils.TestUtil.assertForwardingClassForwardsAllMethods;
import static androidx.media3.test.utils.TestUtil.assertForwardingClassOverridesAllMethods;
import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -28,15 +26,12 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class ForwardingAudioSinkTest { public final class ForwardingAudioSinkTest {
@Test @Test
public void forwardingAudioSink_overridesAllAudioSinkMethods() throws NoSuchMethodException { public void overridesAllMethods() throws NoSuchMethodException {
// Check with reflection that ForwardingAudioSink overrides all AudioSink methods. assertForwardingClassOverridesAllMethods(AudioSink.class, ForwardingAudioSink.class);
List<Method> methods = TestUtil.getPublicMethods(AudioSink.class); }
for (Method method : methods) {
assertThat( @Test
ForwardingAudioSink.class public void forwardsAllMethods() throws Exception {
.getDeclaredMethod(method.getName(), method.getParameterTypes()) assertForwardingClassForwardsAllMethods(AudioSink.class, ForwardingAudioSink::new);
.getDeclaringClass())
.isEqualTo(ForwardingAudioSink.class);
}
} }
} }

View File

@ -0,0 +1,38 @@
/*
* Copyright 2024 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 androidx.media3.extractor;
import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link ForwardingExtractorInput}. */
@RunWith(AndroidJUnit4.class)
public class ForwardingExtractorInputTest {
@Test
public void overridesAllMethods() throws Exception {
TestUtil.assertForwardingClassOverridesAllMethods(
ExtractorInput.class, ForwardingExtractorInput.class);
}
@Test
public void forwardsAllMethods() throws Exception {
TestUtil.assertForwardingClassForwardsAllMethods(
ExtractorInput.class, ForwardingExtractorInput::new);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2024 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 androidx.media3.extractor;
import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link ForwardingSeekMap}. */
@RunWith(AndroidJUnit4.class)
public class ForwardingSeekMapTest {
@Test
public void overridesAllMethods() throws Exception {
TestUtil.assertForwardingClassOverridesAllMethods(SeekMap.class, ForwardingSeekMap.class);
}
@Test
public void forwardsAllMethods() throws Exception {
TestUtil.assertForwardingClassForwardsAllMethods(SeekMap.class, ForwardingSeekMap::new);
}
}

View File

@ -15,12 +15,8 @@
*/ */
package androidx.media3.extractor; package androidx.media3.extractor;
import static com.google.common.truth.Truth.assertThat;
import androidx.media3.test.utils.TestUtil; import androidx.media3.test.utils.TestUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -28,15 +24,13 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ForwardingTrackOutputTest { public class ForwardingTrackOutputTest {
@Test @Test
public void forwardingTrackOutput_overridesAllMethods() throws NoSuchMethodException { public void overridesAllMethods() throws Exception {
// Check with reflection that ForwardingTrackOutput overrides all TrackOutput methods. TestUtil.assertForwardingClassOverridesAllMethods(
List<Method> methods = TestUtil.getPublicMethods(TrackOutput.class); TrackOutput.class, ForwardingTrackOutput.class);
for (Method method : methods) { }
assertThat(
ForwardingTrackOutput.class @Test
.getDeclaredMethod(method.getName(), method.getParameterTypes()) public void forwardsAllMethods() throws Exception {
.getDeclaringClass()) TestUtil.assertForwardingClassForwardsAllMethods(TrackOutput.class, ForwardingTrackOutput::new);
.isEqualTo(ForwardingTrackOutput.class);
}
} }
} }

View File

@ -57,6 +57,7 @@ import androidx.media3.extractor.metadata.MetadataInputBuffer;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.BoundType; import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Range; import com.google.common.collect.Range;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
@ -644,6 +645,19 @@ public class TestUtil {
* Use reflection to assert calling every method declared on {@code superType} on an instance of * 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. * {@code forwardingType} results in the call being forwarded to the {@code superType} delegate.
*/ */
public static <T extends @NonNull Object, F extends T>
void assertForwardingClassForwardsAllMethods(
Class<T> superType, Function<T, F> forwardingInstanceFactory)
throws InvocationTargetException, IllegalAccessException {
assertForwardingClassForwardsAllMethodsExcept(
superType, forwardingInstanceFactory, /* excludedMethods= */ ImmutableSet.of());
}
/**
* Use reflection to assert calling every non-excluded method declared on {@code superType} on an
* instance of {@code forwardingType} results in the call being forwarded to the {@code superType}
* delegate.
*/
// The nullness checker is deliberately over-conservative and doesn't permit passing a null // The nullness checker is deliberately over-conservative and doesn't permit passing a null
// parameter to method.invoke(), even if the real method does accept null. Regardless, we expect // parameter to method.invoke(), even if the real method does accept null. Regardless, we expect
// the null to be passed straight to our mocked delegate, so it's OK to pass null even for // the null to be passed straight to our mocked delegate, so it's OK to pass null even for
@ -651,10 +665,13 @@ public class TestUtil {
// https://github.com/typetools/checker-framework/blob/c26bb695ebc572fac1e9cd2e331fc5b9d3953ec0/checker/jdk/nullness/src/java/lang/reflect/Method.java#L109 // https://github.com/typetools/checker-framework/blob/c26bb695ebc572fac1e9cd2e331fc5b9d3953ec0/checker/jdk/nullness/src/java/lang/reflect/Method.java#L109
@SuppressWarnings("nullness:argument.type.incompatible") @SuppressWarnings("nullness:argument.type.incompatible")
public static <T extends @NonNull Object, F extends T> public static <T extends @NonNull Object, F extends T>
void assertForwardingClassForwardsAllMethods( void assertForwardingClassForwardsAllMethodsExcept(
Class<T> superType, Function<T, F> forwardingInstanceFactory) Class<T> superType, Function<T, F> forwardingInstanceFactory, Set<String> excludedMethods)
throws InvocationTargetException, IllegalAccessException { throws InvocationTargetException, IllegalAccessException {
for (Method method : getPublicMethods(superType)) { for (Method method : getPublicMethods(superType)) {
if (excludedMethods.contains(method.getName())) {
continue;
}
T delegate = mock(superType); T delegate = mock(superType);
F forwardingInstance = forwardingInstanceFactory.apply(delegate); F forwardingInstance = forwardingInstanceFactory.apply(delegate);
@NullableType Object[] parameters = new Object[method.getParameterCount()]; @NullableType Object[] parameters = new Object[method.getParameterCount()];