package com.mopub.mobileads; import android.app.Activity; import android.content.Context; import android.location.Location; import android.view.View; import com.mopub.common.AdReport; import com.mopub.common.DataKeys; import com.mopub.common.test.support.SdkTestRunner; import com.mopub.mobileads.factories.CustomEventBannerFactory; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.Robolectric; import java.util.HashMap; import java.util.Map; import static com.mopub.mobileads.CustomEventBanner.CustomEventBannerListener; import static com.mopub.mobileads.MoPubErrorCode.ADAPTER_CONFIGURATION_ERROR; import static com.mopub.mobileads.MoPubErrorCode.NETWORK_TIMEOUT; import static com.mopub.mobileads.MoPubErrorCode.UNSPECIFIED; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(SdkTestRunner.class) public class CustomEventBannerAdapterTest { private CustomEventBannerAdapter subject; @Mock private MoPubView moPubView; @Mock private AdReport mockAdReport; private static final String CLASS_NAME = "arbitrary_banner_adapter_class_name"; private static final long BROADCAST_IDENTIFIER = 123; private Map<String, String> serverExtras; private CustomEventBanner banner; private Map<String,Object> expectedLocalExtras; private HashMap<String,String> expectedServerExtras; @Before public void setUp() throws Exception { when(moPubView.getAdTimeoutDelay()).thenReturn(null); serverExtras = new HashMap<String, String>(); serverExtras.put("key", "value"); serverExtras.put("another_key", "another_value"); subject = new CustomEventBannerAdapter(moPubView, CLASS_NAME, serverExtras, BROADCAST_IDENTIFIER, mockAdReport); expectedLocalExtras = new HashMap<String, Object>(); expectedLocalExtras.put(DataKeys.AD_REPORT_KEY, mockAdReport); expectedLocalExtras.put("broadcastIdentifier", BROADCAST_IDENTIFIER); expectedServerExtras = new HashMap<String, String>(); banner = CustomEventBannerFactory.create(CLASS_NAME); } @Test public void timeout_shouldSignalFailureAndInvalidateWithDefaultDelay() throws Exception { subject.loadAd(); Robolectric.idleMainLooper(CustomEventBannerAdapter.DEFAULT_BANNER_TIMEOUT_DELAY - 1); verify(moPubView, never()).loadFailUrl(eq(NETWORK_TIMEOUT)); assertThat(subject.isInvalidated()).isFalse(); Robolectric.idleMainLooper(1); verify(moPubView).loadFailUrl(eq(NETWORK_TIMEOUT)); assertThat(subject.isInvalidated()).isTrue(); } @Test public void timeout_withNegativeAdTimeoutDelay_shouldSignalFailureAndInvalidateWithDefaultDelay() throws Exception { when(moPubView.getAdTimeoutDelay()).thenReturn(-1); subject.loadAd(); Robolectric.idleMainLooper(CustomEventBannerAdapter.DEFAULT_BANNER_TIMEOUT_DELAY - 1); verify(moPubView, never()).loadFailUrl(eq(NETWORK_TIMEOUT)); assertThat(subject.isInvalidated()).isFalse(); Robolectric.idleMainLooper(1); verify(moPubView).loadFailUrl(eq(NETWORK_TIMEOUT)); assertThat(subject.isInvalidated()).isTrue(); } @Test public void timeout_withNonNullAdTimeoutDelay_shouldSignalFailureAndInvalidateWithCustomDelay() throws Exception { when(moPubView.getAdTimeoutDelay()).thenReturn(77); subject.loadAd(); Robolectric.idleMainLooper(77000 - 1); verify(moPubView, never()).loadFailUrl(eq(NETWORK_TIMEOUT)); assertThat(subject.isInvalidated()).isFalse(); Robolectric.idleMainLooper(1); verify(moPubView).loadFailUrl(eq(NETWORK_TIMEOUT)); assertThat(subject.isInvalidated()).isTrue(); } @Test public void loadAd_shouldPropagateLocationInLocalExtras() throws Exception { Location expectedLocation = new Location(""); expectedLocation.setLongitude(10.0); expectedLocation.setLongitude(20.1); when(moPubView.getLocation()).thenReturn(expectedLocation); subject = new CustomEventBannerAdapter(moPubView, CLASS_NAME, new HashMap<String, String>(), BROADCAST_IDENTIFIER, mockAdReport); subject.loadAd(); expectedLocalExtras.put("location", moPubView.getLocation()); verify(banner).loadBanner( any(Context.class), eq(subject), eq(expectedLocalExtras), eq(expectedServerExtras) ); } @Test public void loadAd_shouldPropagateServerExtrasToLoadBanner() throws Exception { subject.loadAd(); expectedServerExtras.put("key", "value"); expectedServerExtras.put("another_key", "another_value"); verify(banner).loadBanner( any(Context.class), eq(subject), eq(expectedLocalExtras), eq(expectedServerExtras) ); } @Test public void loadAd_shouldScheduleTimeout_bannerLoadedAndFailed_shouldCancelTimeout() throws Exception { Robolectric.pauseMainLooper(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); subject.loadAd(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.onBannerLoaded(null); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); subject.loadAd(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.onBannerFailed(null); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); } @Test public void loadAd_shouldScheduleTimeoutRunnableBeforeCallingLoadBanner() throws Exception { Robolectric.pauseMainLooper(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); Answer assertTimeoutRunnableHasStarted = new Answer() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); return null; } }; doAnswer(assertTimeoutRunnableHasStarted) .when(banner) .loadBanner( any(Context.class), any(CustomEventBannerListener.class), any(Map.class), any(Map.class) ); subject.loadAd(); } @Test public void loadAd_whenCallingOnBannerFailed_shouldCancelExistingTimeoutRunnable() throws Exception { Robolectric.pauseMainLooper(); Answer justCallOnBannerFailed = new Answer() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.onBannerFailed(null); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); return null; } }; doAnswer(justCallOnBannerFailed) .when(banner) .loadBanner( any(Context.class), any(CustomEventBannerListener.class), any(Map.class), any(Map.class) ); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); subject.loadAd(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); } @Test public void onBannerLoaded_shouldSignalMoPubView() throws Exception { View view = new View(new Activity()); subject.onBannerLoaded(view); verify(moPubView).nativeAdLoaded(); verify(moPubView).setAdContentView(eq(view)); verify(moPubView).trackNativeImpression(); } @Test public void onBannerLoaded_whenViewIsHtmlBannerWebView_shouldNotTrackImpression() throws Exception { View mockHtmlBannerWebView = mock(HtmlBannerWebView.class); subject.onBannerLoaded(mockHtmlBannerWebView); verify(moPubView).nativeAdLoaded(); verify(moPubView).setAdContentView(eq(mockHtmlBannerWebView)); verify(moPubView, never()).trackNativeImpression(); } @Test public void onBannerFailed_shouldLoadFailUrl() throws Exception { subject.onBannerFailed(ADAPTER_CONFIGURATION_ERROR); verify(moPubView).loadFailUrl(eq(ADAPTER_CONFIGURATION_ERROR)); } @Test public void onBannerFailed_whenErrorCodeIsNull_shouldPassUnspecifiedError() throws Exception { subject.onBannerFailed(null); verify(moPubView).loadFailUrl(eq(UNSPECIFIED)); } @Test public void onBannerExpanded_shouldPauseRefreshAndCallAdPresentOverlay() throws Exception { subject.onBannerExpanded(); verify(moPubView).setAutorefreshEnabled(eq(false)); verify(moPubView).adPresentedOverlay(); } @Test public void onBannerCollapsed_shouldRestoreRefreshSettingAndCallAdClosed() throws Exception { when(moPubView.getAutorefreshEnabled()).thenReturn(true); subject.onBannerExpanded(); reset(moPubView); subject.onBannerCollapsed(); verify(moPubView).setAutorefreshEnabled(eq(true)); verify(moPubView).adClosed(); when(moPubView.getAutorefreshEnabled()).thenReturn(false); subject.onBannerExpanded(); reset(moPubView); subject.onBannerCollapsed(); verify(moPubView).setAutorefreshEnabled(eq(false)); verify(moPubView).adClosed(); } @Test public void onBannerClicked_shouldRegisterClick() throws Exception { subject.onBannerClicked(); verify(moPubView).registerClick(); } @Test public void onLeaveApplication_shouldRegisterClick() throws Exception { subject.onLeaveApplication(); verify(moPubView).registerClick(); } @Test public void invalidate_shouldCauseLoadAdToDoNothing() throws Exception { subject.invalidate(); subject.loadAd(); verify(banner, never()).loadBanner( any(Context.class), any(CustomEventBannerListener.class), any(Map.class), any(Map.class) ); } @Test public void invalidate_shouldCauseBannerListenerMethodsToDoNothing() throws Exception { subject.invalidate(); subject.onBannerLoaded(null); subject.onBannerFailed(null); subject.onBannerExpanded(); subject.onBannerCollapsed(); subject.onBannerClicked(); subject.onLeaveApplication(); verify(moPubView, never()).nativeAdLoaded(); verify(moPubView, never()).setAdContentView(any(View.class)); verify(moPubView, never()).trackNativeImpression(); verify(moPubView, never()).loadFailUrl(any(MoPubErrorCode.class)); verify(moPubView, never()).setAutorefreshEnabled(any(boolean.class)); verify(moPubView, never()).adClosed(); verify(moPubView, never()).registerClick(); } }