package com.mopub.mobileads;
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import com.mopub.common.AdReport;
import com.mopub.common.test.support.SdkTestRunner;
import com.mopub.mobileads.test.support.GestureUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static com.mopub.mobileads.AdAlertGestureListener.ZigZagState.FAILED;
import static com.mopub.mobileads.AdAlertGestureListener.ZigZagState.FINISHED;
import static com.mopub.mobileads.AdAlertGestureListener.ZigZagState.GOING_LEFT;
import static com.mopub.mobileads.AdAlertGestureListener.ZigZagState.GOING_RIGHT;
import static com.mopub.mobileads.AdAlertGestureListener.ZigZagState.UNSET;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.stub;
@RunWith(SdkTestRunner.class)
public class AdAlertGestureListenerTest {
@Mock
private View mockView;
@Mock
private AdReport mockAdReport;
private AdAlertGestureListener subject;
private float threshold;
private static final float INITIAL_X = 20;
private static final float INITIAL_Y = 50;
private float savedX;
private float savedY;
private MotionEvent actionDown;
@Mock
private Context mockContext;
@Before
public void setup() {
stub(mockView.getContext()).toReturn(mockContext);
subject = new AdAlertGestureListener(mockView, mockAdReport);
savedX = INITIAL_X;
savedY = INITIAL_Y;
actionDown = GestureUtils.createActionDown(INITIAL_X, INITIAL_Y);
threshold = subject.getMinimumDipsInZigZag();
}
@Test
public void constructor_shouldSetThresholdToOneThirdOfViewsWidth() throws Exception {
stub(mockView.getWidth()).toReturn(150);
subject = new AdAlertGestureListener(mockView, mockAdReport);
assertThat(subject.getMinimumDipsInZigZag()).isEqualTo(50);
}
@Test
public void constructor_whenViewWidthIsWiderThanThreeTimesMaxThreshold_shouldSetThresholdTo100() throws Exception {
stub(mockView.getWidth()).toReturn(500);
subject = new AdAlertGestureListener(mockView, mockAdReport);
assertThat(subject.getMinimumDipsInZigZag()).isEqualTo(100);
}
@Test
public void constructor_whenViewWidthIs0_shouldSetThresholdTo100() throws Exception {
stub(mockView.getWidth()).toReturn(0);
subject = new AdAlertGestureListener(mockView, mockAdReport);
assertThat(subject.getMinimumDipsInZigZag()).isEqualTo(100);
}
@Test
public void shouldDefaultToNoZigZagsCompletedAnd100DipsInZigZag() throws Exception {
assertThat(subject.getNumberOfZigzags()).isEqualTo(0);
assertThat(subject.getMinimumDipsInZigZag()).isEqualTo(100);
assertZigZagState(UNSET);
}
@Test
public void onScroll_withInitialRightMovement_shouldSetStateToGoingRight() throws Exception {
simulateScroll(INITIAL_X);
assertZigZagState(UNSET);
simulateScroll(INITIAL_X + 1);
assertZigZagState(GOING_RIGHT);
}
@Test
public void onScroll_withInitialLeftThenRightMovement_whenRightMovementPassesInitialX_shouldSetStateToGoingRight() throws Exception {
simulateScroll(INITIAL_X);
assertZigZagState(UNSET);
simulateScroll(INITIAL_X - 10);
assertZigZagState(UNSET);
simulateScroll(INITIAL_X - 5);
assertZigZagState(UNSET);
simulateScroll(INITIAL_X + 1);
assertZigZagState(GOING_RIGHT);
}
@Test
public void onScroll_withInitialLeftThenRightMovement_BeforeZigCompletes_MovesOutOfUpperYBounds_shouldSetStateToFailed() throws Exception {
simulateScroll(INITIAL_X);
assertZigZagState(UNSET);
simulateScroll(INITIAL_X + 10);
assertZigZagState(GOING_RIGHT);
simulateScroll(savedX, INITIAL_Y + 49);
assertZigZagState(GOING_RIGHT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(0);
simulateScroll(savedX, INITIAL_Y + 102);
assertZigZagState(FAILED);
}
@Test
public void onScroll_withInitialLeftThenRightMovement_BeforeZigCompletes_MovesOutOfLowerYBounds_shouldSetStateToFailed() throws Exception {
simulateScroll(INITIAL_X);
assertZigZagState(UNSET);
simulateScroll(INITIAL_X + 10);
assertZigZagState(GOING_RIGHT);
simulateScroll(savedX, INITIAL_Y - 49);
assertZigZagState(GOING_RIGHT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(0);
simulateScroll(savedX, INITIAL_Y - 101);
assertZigZagState(FAILED);
}
@Test
public void onScroll_withZigZagZigZagZigZagZig_BeforeNextZagCompletes_MovesOutOfUpperYBounds_shouldSetStateToFailed() throws Exception {
performZigZag();
performZigZag();
performZigZag();
performZig();
simulateScroll(savedX, INITIAL_Y + 49);
assertZigZagState(GOING_RIGHT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(3);
simulateScroll(savedX, INITIAL_Y + 101);
assertZigZagState(FAILED);
}
@Test
public void onScroll_withZigZagZigZagZigZagZig_BeforeNextZagCompletes_MovesOutOfLowerYBounds_shouldSetStateToFailed() throws Exception {
performZigZag();
performZigZag();
performZigZag();
performZig();
simulateScroll(savedX - 1, INITIAL_Y - 49);
assertZigZagState(GOING_LEFT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(3);
simulateScroll(savedX, INITIAL_Y - 101);
assertZigZagState(FAILED);
}
@Test
public void onScroll_withStateFailed_withAnyMotion_shouldStayFailed() throws Exception {
simulateScroll(savedX, INITIAL_Y + 49);
simulateScroll(savedX, INITIAL_Y + 101);
assertZigZagState(FAILED);
performZigZag();
assertZigZagState(FAILED);
performZig();
assertZigZagState(FAILED);
performZag();
assertZigZagState(FAILED);
}
@Test
public void onScroll_whenGoingRightPastThreshold_thenGoingLeft_shouldSetStateToGoingLeft() throws Exception {
simulateScroll(INITIAL_X);
simulateScroll(INITIAL_X + threshold);
simulateScroll(INITIAL_X + threshold + 2);
assertZigZagState(GOING_RIGHT);
simulateScroll(INITIAL_X + threshold - 1);
assertZigZagState(GOING_LEFT);
}
@Test
public void onScroll_withCompleteZigZag_shouldSetStateToGoingLeftAndNumberOfZigZagsIs1() throws Exception {
performZig();
assertZigZagState(GOING_RIGHT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(0);
performZag();
assertZigZagState(GOING_LEFT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(1);
}
@Test
public void onScroll_withZig_butBeforeZagIsComplete_shouldKeepStateGoingLeftButNotIncrementZigZags() throws Exception {
performZig();
assertZigZagState(GOING_RIGHT);
simulateScroll(INITIAL_X + threshold - 5);
assertZigZagState(GOING_LEFT);
// we turn back prematurely
simulateScroll(INITIAL_X + threshold);
assertZigZagState(GOING_LEFT);
assertThat(subject.getNumberOfZigzags()).isEqualTo(0);
}
@Test
public void onScroll_withZigZagZig_butTurningLeftBeforeSecondZigIsComplete_shouldKeepStateGoingRightButNotReachRightThreshold() throws Exception {
performZigZag();
assertZigZagState(GOING_LEFT);
simulateScroll(INITIAL_X + 10);
assertZigZagState(GOING_RIGHT);
simulateScroll(INITIAL_X);
assertZigZagState(GOING_RIGHT);
}
@Test
public void checkReportAd_withZigZagThreeTimes_shouldNotAlertFlagAndSetStateToUnset() throws Exception {
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(1);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(2);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(3);
subject.finishGestureDetection();
assertThat(subject.getAdAlertReporter()).isNull();
assertZigZagState(UNSET);
}
@Test
public void onScroll_withFourZigZags_shouldSetStateToFinished() throws Exception {
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(1);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(2);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(3);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
assertZigZagState(FINISHED);
}
@Test
public void checkReportAd_withZigZagFourTimes_shouldAlertFlagAndSetStateToUnset() throws Exception {
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(1);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(2);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(3);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
subject.finishGestureDetection();
assertThat(subject.getAdAlertReporter()).isNotNull();
assertZigZagState(UNSET);
}
@Test
public void checkReportAd_withZigZagTenTimes_shouldAlertFlag_andNotIncrementZigZagCount_andSetStateToFinished() throws Exception {
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(1);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(2);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(3);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
performZigZag();
assertThat(subject.getNumberOfZigzags()).isEqualTo(4);
subject.finishGestureDetection();
assertThat(subject.getAdAlertReporter()).isNotNull();
assertZigZagState(UNSET);
}
@Test
public void reset_shouldResetStateAndZigZagCount() throws Exception {
performZigZag();
performZig();
subject.reset();
assertThat(subject.getNumberOfZigzags()).isEqualTo(0);
assertZigZagState(UNSET);
}
private void simulateScroll(float endX) {
simulateScroll(endX, savedY);
}
private void simulateScroll(float endX, float endY) {
final float stepSizeX = Math.signum(endX - savedX) * 0.5f;
final float stepSizeY = Math.signum(endY - savedY) * 0.5f;
float x = savedX;
float y = savedY;
if (areEqual(savedX, endX)) {
subject.onScroll(actionDown, GestureUtils.createActionMove(x, y), 0, 0);
} else if (savedX < endX) {
for (; x < endX; x += stepSizeX) {
subject.onScroll(actionDown, GestureUtils.createActionMove(x, y), 0, 0);
}
} else if (savedX > endX) {
for (; x > endX; x += stepSizeX) {
subject.onScroll(actionDown, GestureUtils.createActionMove(x, y), 0, 0);
}
}
if (areEqual(savedY, endY)) {
subject.onScroll(actionDown, GestureUtils.createActionMove(x, y), 0, 0);
} else if (savedY < endY) {
for (; y < endY; y += stepSizeY) {
subject.onScroll(actionDown, GestureUtils.createActionMove(x, y), 0, 0);
}
} else if (savedY > endY) {
for (; y > endY; y += stepSizeY) {
subject.onScroll(actionDown, GestureUtils.createActionMove(x, y), 0, 0);
}
}
savedX = endX;
savedY = endY;
}
private void performZig() {
simulateScroll(savedX + threshold + 1);
}
private void performZag() {
simulateScroll(savedX - threshold - 1);
}
private void performZigZag() {
performZig();
performZag();
}
private boolean areEqual(float a, float b) {
return (Math.abs(a - b) < 0.01f);
}
private void assertZigZagState(AdAlertGestureListener.ZigZagState state) {
assertThat(subject.getCurrentZigZagState()).isEqualTo(state);
}
}