/*
* Copyright (C) 2013 Square, Inc.
*
* 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 com.squareup.picasso;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.robolectric.RobolectricTestRunner;
import static com.squareup.picasso.TestUtils.TRANSFORM_REQUEST_ANSWER;
import static com.squareup.picasso.TestUtils.URI_1;
import static com.squareup.picasso.TestUtils.mockCallback;
import static com.squareup.picasso.TestUtils.mockFitImageViewTarget;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
@RunWith(RobolectricTestRunner.class)
public class DeferredRequestCreatorTest {
@Captor ArgumentCaptor<Action> actionCaptor;
@Before public void setUp() {
initMocks(this);
}
@Test public void initWhileAttachedAddsAttachAndPreDrawListener() {
ImageView target = mockFitImageViewTarget(true);
ViewTreeObserver observer = target.getViewTreeObserver();
DeferredRequestCreator request =
new DeferredRequestCreator(mock(RequestCreator.class), target, null);
verify(observer).addOnPreDrawListener(request);
}
@Test public void initWhileDetachedAddsAttachListenerWhichDefersPreDrawListener() {
ImageView target = mockFitImageViewTarget(true);
when(target.getWindowToken()).thenReturn(null);
ViewTreeObserver observer = target.getViewTreeObserver();
DeferredRequestCreator request =
new DeferredRequestCreator(mock(RequestCreator.class), target, null);
verify(target).addOnAttachStateChangeListener(request);
verifyNoMoreInteractions(observer);
// Attach and ensure we defer to the pre-draw listener.
request.onViewAttachedToWindow(target);
verify(observer).addOnPreDrawListener(request);
// Detach and ensure we remove the pre-draw listener from the original VTO.
request.onViewDetachedFromWindow(target);
verify(observer).removeOnPreDrawListener(request);
}
@Test public void cancelWhileAttachedRemovesAttachListener() {
ImageView target = mockFitImageViewTarget(true);
DeferredRequestCreator request = new DeferredRequestCreator(mock(RequestCreator.class), target, null);
verify(target).addOnAttachStateChangeListener(request);
request.cancel();
verify(target).removeOnAttachStateChangeListener(request);
}
@Test public void cancelTwiceWhileAttachedOnlyPerformsOnce() {
ImageView target = mockFitImageViewTarget(true);
ViewTreeObserver observer = target.getViewTreeObserver();
DeferredRequestCreator request = new DeferredRequestCreator(mock(RequestCreator.class), target, null);
request.cancel();
request.cancel();
verify(observer).removeOnPreDrawListener(request);
}
@Test public void cancelClearsCallback() {
ImageView target = mockFitImageViewTarget(true);
Callback callback = mockCallback();
DeferredRequestCreator request =
new DeferredRequestCreator(mock(RequestCreator.class), target, callback);
assertThat(request.callback).isNotNull();
request.cancel();
assertThat(request.callback).isNull();
}
@Test public void cancelClearsTag() {
ImageView target = mockFitImageViewTarget(true);
RequestCreator creator = mock(RequestCreator.class);
when(creator.getTag()).thenReturn("TAG");
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.cancel();
verify(creator).clearTag();
}
@Test public void onLayoutSkipsIfTargetIsNullAfterAttach() {
ImageView target = mockFitImageViewTarget(true);
RequestCreator creator = mock(RequestCreator.class);
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
ViewTreeObserver viewTreeObserver = target.getViewTreeObserver();
request.target.clear();
request.onPreDraw();
verifyZeroInteractions(creator);
verify(viewTreeObserver).addOnPreDrawListener(request);
verifyNoMoreInteractions(viewTreeObserver);
}
@Test public void onLayoutSkipsIfViewIsAttachedAndViewTreeObserverIsDead() {
ImageView target = mockFitImageViewTarget(false);
RequestCreator creator = mock(RequestCreator.class);
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
ViewTreeObserver viewTreeObserver = target.getViewTreeObserver();
request.onPreDraw();
verify(viewTreeObserver).addOnPreDrawListener(request);
verify(viewTreeObserver).isAlive();
verifyNoMoreInteractions(viewTreeObserver);
verifyZeroInteractions(creator);
}
@Test public void waitsForAnotherLayoutIfWidthOrHeightIsZero() {
ImageView target = mockFitImageViewTarget(true);
when(target.getWidth()).thenReturn(0);
when(target.getHeight()).thenReturn(0);
RequestCreator creator = mock(RequestCreator.class);
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.onPreDraw();
verify(target.getViewTreeObserver(), never()).removeOnPreDrawListener(request);
verifyZeroInteractions(creator);
}
@Test public void waitsForAnotherLayoutIfLayoutRequested() {
ImageView target = mockFitImageViewTarget(true);
when(target.getWidth()).thenReturn(100);
when(target.getHeight()).thenReturn(100);
when(target.isLayoutRequested()).thenReturn(true);
RequestCreator creator = mock(RequestCreator.class);
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.onPreDraw();
verify(target.getViewTreeObserver(), never()).removeOnPreDrawListener(request);
verifyZeroInteractions(creator);
}
@Test public void cancelSkipsWithNullTarget() {
ImageView target = mockFitImageViewTarget(true);
RequestCreator creator = mock(RequestCreator.class);
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.target.clear();
request.cancel();
verify(target.getViewTreeObserver(), never()).removeOnPreDrawListener(request);
}
@Test public void cancelSkipsIfViewTreeObserverIsDead() {
ImageView target = mockFitImageViewTarget(false);
RequestCreator creator = mock(RequestCreator.class);
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.cancel();
verify(target.getViewTreeObserver(), never()).removeOnPreDrawListener(request);
}
@Test public void preDrawSubmitsRequestAndCleansUp() {
Picasso picasso = mock(Picasso.class);
when(picasso.transformRequest(any(Request.class))).thenAnswer(TRANSFORM_REQUEST_ANSWER);
RequestCreator creator = new RequestCreator(picasso, URI_1, 0);
ImageView target = mockFitImageViewTarget(true);
when(target.getWidth()).thenReturn(100);
when(target.getHeight()).thenReturn(100);
ViewTreeObserver observer = target.getViewTreeObserver();
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.onPreDraw();
verify(observer).removeOnPreDrawListener(request);
verify(picasso).enqueueAndSubmit(actionCaptor.capture());
Action value = actionCaptor.getValue();
assertThat(value).isInstanceOf(ImageViewAction.class);
assertThat(value.getRequest().targetWidth).isEqualTo(100);
assertThat(value.getRequest().targetHeight).isEqualTo(100);
}
@Test public void multiplePreDrawsOnlyTriggersOnce() {
Picasso picasso = mock(Picasso.class);
when(picasso.transformRequest(any(Request.class))).thenAnswer(TRANSFORM_REQUEST_ANSWER);
RequestCreator creator = new RequestCreator(picasso, URI_1, 0);
ImageView target = mockFitImageViewTarget(true);
when(target.getWidth()).thenReturn(100);
when(target.getHeight()).thenReturn(100);
ViewTreeObserver observer = target.getViewTreeObserver();
DeferredRequestCreator request = new DeferredRequestCreator(creator, target, null);
request.onPreDraw();
request.onPreDraw();
verify(observer).removeOnPreDrawListener(request);
verify(picasso).enqueueAndSubmit(actionCaptor.capture());
}
}