package com.bumptech.glide.load.resource.gif; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.gifdecoder.GifHeader; import com.bumptech.glide.gifdecoder.GifHeaderParser; import com.bumptech.glide.load.ImageHeaderParser; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.engine.bitmap_recycle.LruArrayPool; import com.bumptech.glide.load.resource.bitmap.DefaultImageHeaderParser; import com.bumptech.glide.tests.GlideShadowLooper; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE, sdk = 18, shadows = GlideShadowLooper.class) public class ByteBufferGifDecoderTest { private static final byte[] GIF_HEADER = new byte[] { 0x47, 0x49, 0x46 }; static final int ARRAY_POOL_SIZE_BYTES = 4 * 1024 * 1024; private ByteBufferGifDecoder decoder; private GifHeader gifHeader; private Options options; @Mock BitmapPool bitmapPool; @Mock GifHeaderParser parser; @Mock GifDecoder gifDecoder; @Mock ByteBufferGifDecoder.GifHeaderParserPool parserPool; @Mock ByteBufferGifDecoder.GifDecoderFactory decoderFactory; @Before public void setUp() { MockitoAnnotations.initMocks(this); gifHeader = Mockito.spy(new GifHeader()); when(parser.parseHeader()).thenReturn(gifHeader); when(parserPool.obtain(isA(ByteBuffer.class))).thenReturn(parser); when(decoderFactory.build(isA(GifDecoder.BitmapProvider.class), eq(gifHeader), isA(ByteBuffer.class), anyInt())) .thenReturn(gifDecoder); List<ImageHeaderParser> parsers = new ArrayList<ImageHeaderParser>(); parsers.add(new DefaultImageHeaderParser()); options = new Options(); decoder = new ByteBufferGifDecoder( RuntimeEnvironment.application, parsers, bitmapPool, new LruArrayPool(ARRAY_POOL_SIZE_BYTES), parserPool, decoderFactory); } @Test public void testDoesNotHandleStreamIfEnabledButNotAGif() throws IOException { assertThat(decoder.handles(ByteBuffer.allocate(0), options)).isFalse(); } @Test public void testHandlesStreamIfContainsGifHeaderAndDisabledIsNotSet() throws IOException { assertThat(decoder.handles(ByteBuffer.wrap(GIF_HEADER), options)).isTrue(); } @Test public void testHandlesStreamIfContainsGifHeaderAndDisabledIsFalse() throws IOException { options.set(ByteBufferGifDecoder.DISABLE_ANIMATION, false); assertThat(decoder.handles(ByteBuffer.wrap(GIF_HEADER), options)).isTrue(); } @Test public void testDoesNotHandleStreamIfDisabled() throws IOException { options.set(ByteBufferGifDecoder.DISABLE_ANIMATION, true); assertThat(decoder.handles(ByteBuffer.wrap(GIF_HEADER), options)).isFalse(); } @Test public void testReturnsNullIfParsedHeaderHasZeroFrames() throws IOException { when(gifHeader.getNumFrames()).thenReturn(0); assertNull(decoder.decode(ByteBuffer.allocate(10), 100, 100, options)); } @Test public void testReturnsNullIfParsedHeaderHasFormatError() { when(gifHeader.getStatus()).thenReturn(GifDecoder.STATUS_FORMAT_ERROR); assertNull(decoder.decode(ByteBuffer.allocate(10), 100, 100, options)); } @Test public void testReturnsNullIfParsedHeaderHasOpenError() { when(gifHeader.getStatus()).thenReturn(GifDecoder.STATUS_OPEN_ERROR); assertNull(decoder.decode(ByteBuffer.allocate(10), 100, 100, options)); } @Test public void testReturnsParserToPool() throws IOException { decoder.decode(ByteBuffer.allocate(10), 100, 100, options); verify(parserPool).release(eq(parser)); } @Test public void testReturnsParserToPoolWhenParserThrows() { when(parser.parseHeader()).thenThrow(new RuntimeException("Test")); try { decoder.decode(ByteBuffer.allocate(10), 100, 100, options); fail("Failed to receive expected exception"); } catch (RuntimeException e) { // Expected. } verify(parserPool).release(eq(parser)); } @Test public void testReturnsNullIfGifDecoderFailsToDecodeFirstFrame() { when(gifHeader.getNumFrames()).thenReturn(1); when(gifHeader.getStatus()).thenReturn(GifDecoder.STATUS_OK); when(gifDecoder.getNextFrame()).thenReturn(null); assertNull(decoder.decode(ByteBuffer.allocate(10), 100, 100, options)); } }