package com.mopub.mobileads; import android.app.Activity; import android.content.Context; import android.net.ConnectivityManager; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; import com.mopub.common.test.support.SdkTestRunner; import com.mopub.common.util.Reflection; import com.mopub.common.util.test.support.TestMethodBuilderFactory; import com.mopub.mobileads.test.support.ThreadUtils; import com.mopub.network.AdResponse; import com.mopub.network.Networking; import com.mopub.volley.Request; import com.mopub.volley.RequestQueue; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.robolectric.Robolectric; import edu.emory.mathcs.backport.java.util.Collections; import static com.mopub.common.VolleyRequestMatcher.isUrl; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.robolectric.Robolectric.shadowOf; @RunWith(SdkTestRunner.class) public class AdViewControllerTest { private AdViewController subject; @Mock private MoPubView mockMoPubView; @Mock private RequestQueue mockRequestQueue; private Reflection.MethodBuilder methodBuilder; private Activity context; private AdResponse response; @Before public void setup() { context = Robolectric.buildActivity(Activity.class).create().get(); shadowOf(context).grantPermissions(android.Manifest.permission.ACCESS_NETWORK_STATE); when(mockMoPubView.getContext()).thenReturn(context); Networking.setRequestQueueForTesting(mockRequestQueue); subject = new AdViewController(context, mockMoPubView); methodBuilder = TestMethodBuilderFactory.getSingletonMock(); reset(methodBuilder); response = new AdResponse.Builder() .setCustomEventClassName("customEvent") .setClickTrackingUrl("clickUrl") .setImpressionTrackingUrl("impressionUrl") .setRedirectUrl("redirectUrl") .setScrollable(false) .setDimensions(320, 50) .setAdType("html") .setFailoverUrl("failUrl") .setResponseBody("testResponseBody") .setServerExtras(Collections.emptyMap()) .build(); } @After public void tearDown() throws Exception { reset(methodBuilder); } @Test public void scheduleRefreshTimer_shouldNotScheduleIfRefreshTimeIsZero() { response = response.toBuilder().setRefreshTimeMilliseconds(0).build(); subject.onAdLoadSuccess(response); Robolectric.pauseMainLooper(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); subject.scheduleRefreshTimerIfEnabled(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); } @Test public void scheduleRefreshTimerIfEnabled_shouldCancelOldRefreshAndScheduleANewOne() throws Exception { response = response.toBuilder().setRefreshTimeMilliseconds(30).build(); subject.onAdLoadSuccess(response); Robolectric.pauseMainLooper(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.scheduleRefreshTimerIfEnabled(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.scheduleRefreshTimerIfEnabled(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); } @Test public void scheduleRefreshTimer_shouldNotScheduleRefreshIfAutorefreshIsOff() throws Exception { response = response.toBuilder().setRefreshTimeMilliseconds(30).build(); subject.onAdLoadSuccess(response); Robolectric.pauseMainLooper(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.forceSetAutorefreshEnabled(false); subject.scheduleRefreshTimerIfEnabled(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); } @Test public void scheduleRefreshTimer_whenAdViewControllerNotConfiguredByResponse_shouldHaveDefaultRefreshTime() throws Exception { Robolectric.pauseMainLooper(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); subject.scheduleRefreshTimerIfEnabled(); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); Robolectric.idleMainLooper(AdViewController.DEFAULT_REFRESH_TIME_MILLISECONDS - 1); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); Robolectric.idleMainLooper(1); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); } @Test public void forceSetAutoRefreshEnabled_shouldSetAutoRefreshSetting() throws Exception { assertThat(subject.getAutorefreshEnabled()).isTrue(); subject.forceSetAutorefreshEnabled(false); assertThat(subject.getAutorefreshEnabled()).isFalse(); subject.forceSetAutorefreshEnabled(true); assertThat(subject.getAutorefreshEnabled()).isTrue(); } @Test public void pauseRefresh_shouldDisableAutorefresh() throws Exception { assertThat(subject.getAutorefreshEnabled()).isTrue(); subject.pauseRefresh(); assertThat(subject.getAutorefreshEnabled()).isFalse(); } @Test public void unpauseRefresh_afterUnpauseRefresh_shouldEnableRefresh() throws Exception { subject.pauseRefresh(); subject.unpauseRefresh(); assertThat(subject.getAutorefreshEnabled()).isTrue(); } @Test public void pauseAndUnpauseRefresh_withRefreshForceDisabled_shouldAlwaysHaveRefreshFalse() throws Exception { subject.forceSetAutorefreshEnabled(false); assertThat(subject.getAutorefreshEnabled()).isFalse(); subject.pauseRefresh(); assertThat(subject.getAutorefreshEnabled()).isFalse(); subject.unpauseRefresh(); assertThat(subject.getAutorefreshEnabled()).isFalse(); } @Test public void enablingAutoRefresh_afterLoadAd_shouldScheduleNewRefreshTimer() throws Exception { final AdViewController adViewControllerSpy = spy(subject); adViewControllerSpy.loadAd(); adViewControllerSpy.forceSetAutorefreshEnabled(true); verify(adViewControllerSpy).scheduleRefreshTimerIfEnabled(); } @Test public void enablingAutoRefresh_withoutCallingLoadAd_shouldNotScheduleNewRefreshTimer() throws Exception { final AdViewController adViewControllerSpy = spy(subject); adViewControllerSpy.forceSetAutorefreshEnabled(true); verify(adViewControllerSpy, never()).scheduleRefreshTimerIfEnabled(); } @Test public void disablingAutoRefresh_shouldCancelRefreshTimers() throws Exception { response = response.toBuilder().setRefreshTimeMilliseconds(30).build(); subject.onAdLoadSuccess(response); Robolectric.pauseMainLooper(); subject.loadAd(); subject.forceSetAutorefreshEnabled(true); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(1); subject.forceSetAutorefreshEnabled(false); assertThat(Robolectric.getUiThreadScheduler().enqueuedTaskCount()).isEqualTo(0); } @Test public void trackImpression_shouldAddToRequestQueue() throws Exception { subject.onAdLoadSuccess(response); subject.trackImpression(); verify(mockRequestQueue).add(argThat(isUrl("impressionUrl"))); } @Test public void trackImpression_noAdResponse_shouldNotAddToQueue() { subject.trackImpression(); verifyZeroInteractions(mockRequestQueue); } @Test public void registerClick_shouldHttpGetTheClickthroughUrl() throws Exception { subject.onAdLoadSuccess(response); subject.registerClick(); verify(mockRequestQueue).add(argThat(isUrl("clickUrl"))); } @Test public void registerClick_NoAdResponse_shouldNotAddToQueue() { subject.registerClick(); verifyZeroInteractions(mockRequestQueue); } @Test public void loadAd_shouldNotLoadWithoutConnectivity() throws Exception { ConnectivityManager connectivityManager = (ConnectivityManager) Robolectric.application.getSystemService(Context.CONNECTIVITY_SERVICE); shadowOf(connectivityManager.getActiveNetworkInfo()).setConnectionStatus(false); subject.loadAd(); verifyZeroInteractions(mockRequestQueue); } @Test public void loadAd_shouldNotLoadUrlIfAdUnitIdIsNull() throws Exception { subject.loadAd(); verifyZeroInteractions(mockRequestQueue); } @Test public void loadNonJavascript_shouldFetchAd() throws Exception { String url = "http://www.guy.com"; subject.loadNonJavascript(url); verify(mockRequestQueue).add(argThat(isUrl(url))); } @Test public void loadNonJavascript_whenAlreadyLoading_shouldNotFetchAd() throws Exception { String url = "http://www.guy.com"; subject.loadNonJavascript(url); reset(mockRequestQueue); subject.loadNonJavascript(url); verify(mockRequestQueue, never()).add(any(Request.class)); } @Test public void loadNonJavascript_shouldAcceptNullParameter() throws Exception { subject.loadNonJavascript(null); // pass } @Test public void reload_shouldReuseOldUrl() throws Exception { String url = "http://www.guy.com"; subject.loadNonJavascript(url); subject.setNotLoading(); reset(mockRequestQueue); subject.reload(); verify(mockRequestQueue).add(argThat(isUrl(url))); } @Test public void loadFailUrl_shouldLoadFailUrl() throws Exception { subject.onAdLoadSuccess(response); subject.loadFailUrl(MoPubErrorCode.INTERNAL_ERROR); verify(mockRequestQueue).add(argThat(isUrl("failUrl"))); verify(mockMoPubView, never()).adFailed(any(MoPubErrorCode.class)); } @Test public void loadFailUrl_shouldAcceptNullErrorCode() throws Exception { subject.loadFailUrl(null); // pass } @Test public void loadFailUrl_whenFailUrlIsNull_shouldCallAdDidFail() throws Exception { response.toBuilder().setFailoverUrl(null).build(); subject.loadFailUrl(MoPubErrorCode.INTERNAL_ERROR); verify(mockMoPubView).adFailed(eq(MoPubErrorCode.NO_FILL)); verifyZeroInteractions(mockRequestQueue); } @Test public void setAdContentView_whenCalledFromWrongUiThread_shouldStillSetContentView() throws Exception { final View view = mock(View.class); AdViewController.setShouldHonorServerDimensions(view); subject.onAdLoadSuccess(response); new Thread(new Runnable() { @Override public void run() { subject.setAdContentView(view); } }).start(); ThreadUtils.pause(100); Robolectric.runUiThreadTasks(); verify(mockMoPubView).removeAllViews(); ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor = ArgumentCaptor.forClass(FrameLayout.LayoutParams.class); verify(mockMoPubView).addView(eq(view), layoutParamsCaptor.capture()); FrameLayout.LayoutParams layoutParams = layoutParamsCaptor.getValue(); assertThat(layoutParams.width).isEqualTo(320); assertThat(layoutParams.height).isEqualTo(50); assertThat(layoutParams.gravity).isEqualTo(Gravity.CENTER); } @Test public void setAdContentView_whenCalledAfterCleanUp_shouldNotRemoveViewsAndAddView() throws Exception { final View view = mock(View.class); AdViewController.setShouldHonorServerDimensions(view); subject.onAdLoadSuccess(response); subject.cleanup(); new Thread(new Runnable() { @Override public void run() { subject.setAdContentView(view); } }).start(); ThreadUtils.pause(10); Robolectric.runUiThreadTasks(); verify(mockMoPubView, never()).removeAllViews(); verify(mockMoPubView, never()).addView(any(View.class), any(FrameLayout.LayoutParams.class)); } @Test public void setAdContentView_whenHonorServerDimensionsAndHasDimensions_shouldSizeAndCenterView() throws Exception { View view = mock(View.class); AdViewController.setShouldHonorServerDimensions(view); subject.onAdLoadSuccess(response); subject.setAdContentView(view); verify(mockMoPubView).removeAllViews(); ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor = ArgumentCaptor.forClass(FrameLayout.LayoutParams.class); verify(mockMoPubView).addView(eq(view), layoutParamsCaptor.capture()); FrameLayout.LayoutParams layoutParams = layoutParamsCaptor.getValue(); assertThat(layoutParams.width).isEqualTo(320); assertThat(layoutParams.height).isEqualTo(50); assertThat(layoutParams.gravity).isEqualTo(Gravity.CENTER); } @Test public void setAdContentView_whenHonorServerDimensionsAndDoesntHaveDimensions_shouldWrapAndCenterView() throws Exception { response = response.toBuilder().setDimensions(null, null).build(); View view = mock(View.class); AdViewController.setShouldHonorServerDimensions(view); subject.onAdLoadSuccess(response); subject.setAdContentView(view); verify(mockMoPubView).removeAllViews(); ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor = ArgumentCaptor.forClass(FrameLayout.LayoutParams.class); verify(mockMoPubView).addView(eq(view), layoutParamsCaptor.capture()); FrameLayout.LayoutParams layoutParams = layoutParamsCaptor.getValue(); assertThat(layoutParams.width).isEqualTo(FrameLayout.LayoutParams.WRAP_CONTENT); assertThat(layoutParams.height).isEqualTo(FrameLayout.LayoutParams.WRAP_CONTENT); assertThat(layoutParams.gravity).isEqualTo(Gravity.CENTER); } @Test public void setAdContentView_whenNotServerDimensions_shouldWrapAndCenterView() throws Exception { subject.onAdLoadSuccess(response); View view = mock(View.class); subject.setAdContentView(view); verify(mockMoPubView).removeAllViews(); ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor = ArgumentCaptor.forClass(FrameLayout.LayoutParams.class); verify(mockMoPubView).addView(eq(view), layoutParamsCaptor.capture()); FrameLayout.LayoutParams layoutParams = layoutParamsCaptor.getValue(); assertThat(layoutParams.width).isEqualTo(FrameLayout.LayoutParams.WRAP_CONTENT); assertThat(layoutParams.height).isEqualTo(FrameLayout.LayoutParams.WRAP_CONTENT); assertThat(layoutParams.gravity).isEqualTo(Gravity.CENTER); } }