1package org.robolectric.shadows;
2
3import static java.nio.charset.StandardCharsets.UTF_8;
4import static org.assertj.core.api.Assertions.assertThat;
5import static org.junit.Assert.assertEquals;
6import static org.robolectric.Shadows.shadowOf;
7
8import android.graphics.Bitmap;
9import android.graphics.BitmapFactory;
10import android.graphics.Point;
11import android.net.Uri;
12import android.provider.MediaStore;
13import java.io.File;
14import java.io.FileDescriptor;
15import java.io.FileInputStream;
16import java.io.InputStream;
17import org.junit.Test;
18import org.junit.runner.RunWith;
19import org.robolectric.R;
20import org.robolectric.RobolectricTestRunner;
21import org.robolectric.RuntimeEnvironment;
22
23@RunWith(RobolectricTestRunner.class)
24public class ShadowBitmapFactoryTest {
25  @Test
26  public void decodeResource_shouldSetDescriptionAndCreatedFrom() throws Exception {
27    Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image);
28    ShadowBitmap shadowBitmap = shadowOf(bitmap);
29    assertEquals("Bitmap for resource:org.robolectric:drawable/an_image", shadowBitmap.getDescription());
30    assertEquals(R.drawable.an_image, shadowBitmap.getCreatedFromResId());
31    assertEquals(100, bitmap.getWidth());
32    assertEquals(100, bitmap.getHeight());
33  }
34
35  @Test
36  public void decodeResource_shouldSetDefaultBitmapConfig() throws Exception {
37    Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image);
38    assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888);
39    assertThat(bitmap.getRowBytes()).isNotZero();
40  }
41
42  @Test
43  public void withResId0_decodeResource_shouldReturnNull() throws Exception {
44    assertThat(BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), 0)).isNull();
45  }
46
47  @Test
48  public void decodeResource_shouldPassABitmapConfig() throws Exception {
49    BitmapFactory.Options options = new BitmapFactory.Options();
50    options.inPreferredConfig = Bitmap.Config.ALPHA_8;
51    Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image, options);
52    assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ALPHA_8);
53  }
54
55  @Test
56  public void decodeFile_shouldSetDescriptionAndCreatedFrom() throws Exception {
57    Bitmap bitmap = BitmapFactory.decodeFile("/some/file.jpg");
58    ShadowBitmap shadowBitmap = shadowOf(bitmap);
59    assertEquals("Bitmap for file:/some/file.jpg", shadowBitmap.getDescription());
60    assertEquals("/some/file.jpg", shadowBitmap.getCreatedFromPath());
61    assertEquals(100, bitmap.getWidth());
62    assertEquals(100, bitmap.getHeight());
63  }
64
65  @Test
66  public void decodeStream_shouldSetDescriptionAndCreatedFrom() throws Exception {
67    InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path"));
68    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
69    ShadowBitmap shadowBitmap = shadowOf(bitmap);
70    assertEquals("Bitmap for content:/path", shadowBitmap.getDescription());
71    assertEquals(inputStream, shadowBitmap.getCreatedFromStream());
72    assertEquals(100, bitmap.getWidth());
73    assertEquals(100, bitmap.getHeight());
74    bitmap.getPixels(new int[bitmap.getHeight() * bitmap.getWidth()], 0, 0, 0, 0, bitmap.getWidth(), bitmap.getHeight());
75  }
76
77  @Test
78  public void decodeBytes_shouldSetDescriptionAndCreatedFrom() throws Exception {
79    byte[] yummyBites = "Hi!".getBytes("UTF-8");
80    Bitmap bitmap = BitmapFactory.decodeByteArray(yummyBites, 100, 100);
81    ShadowBitmap shadowBitmap = shadowOf(bitmap);
82    assertEquals("Bitmap for Hi! bytes 100..100", shadowBitmap.getDescription());
83    assertEquals(yummyBites, shadowBitmap.getCreatedFromBytes());
84    assertEquals(100, bitmap.getWidth());
85    assertEquals(100, bitmap.getHeight());
86  }
87
88  @Test
89  public void decodeStream_shouldSetDescriptionWithNullOptions() throws Exception {
90    InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path"));
91    Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, null);
92    assertEquals("Bitmap for content:/path", shadowOf(bitmap).getDescription());
93    assertEquals(100, bitmap.getWidth());
94    assertEquals(100, bitmap.getHeight());
95  }
96
97  @Test
98  public void decodeResource_shouldGetWidthAndHeightFromHints() throws Exception {
99    ShadowBitmapFactory.provideWidthAndHeightHints(R.drawable.an_image, 123, 456);
100
101    Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image);
102    assertEquals("Bitmap for resource:org.robolectric:drawable/an_image", shadowOf(bitmap).getDescription());
103    assertEquals(123, bitmap.getWidth());
104    assertEquals(456, bitmap.getHeight());
105  }
106
107  @Test
108  public void decodeResource_canTakeOptions() throws Exception {
109    BitmapFactory.Options options = new BitmapFactory.Options();
110    options.inSampleSize = 100;
111    Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image, options);
112    assertEquals(true, shadowOf(bitmap).getDescription().contains("inSampleSize=100"));
113  }
114
115  @Test
116  public void decodeResourceStream_canTakeOptions() throws Exception {
117    BitmapFactory.Options options = new BitmapFactory.Options();
118    InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path"));
119    options.inSampleSize = 100;
120    Bitmap bitmap = BitmapFactory.decodeResourceStream(RuntimeEnvironment.application.getResources(), null, inputStream, null, options);
121    assertEquals(true, shadowOf(bitmap).getDescription().contains("inSampleSize=100"));
122  }
123
124  @Test
125  public void decodeFile_shouldGetWidthAndHeightFromHints() throws Exception {
126    ShadowBitmapFactory.provideWidthAndHeightHints("/some/file.jpg", 123, 456);
127
128    Bitmap bitmap = BitmapFactory.decodeFile("/some/file.jpg");
129    assertEquals("Bitmap for file:/some/file.jpg", shadowOf(bitmap).getDescription());
130    assertEquals(123, bitmap.getWidth());
131    assertEquals(456, bitmap.getHeight());
132  }
133
134  @Test
135  public void decodeFileEtc_shouldSetOptionsOutWidthAndOutHeightFromHints() throws Exception {
136    ShadowBitmapFactory.provideWidthAndHeightHints("/some/file.jpg", 123, 456);
137
138    BitmapFactory.Options options = new BitmapFactory.Options();
139    BitmapFactory.decodeFile("/some/file.jpg", options);
140    assertEquals(123, options.outWidth);
141    assertEquals(456, options.outHeight);
142  }
143
144  @Test
145  public void decodeUri_shouldGetWidthAndHeightFromHints() throws Exception {
146    ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse("content:/path"), 123, 456);
147
148    Bitmap bitmap = MediaStore.Images.Media.getBitmap(RuntimeEnvironment.application.getContentResolver(), Uri.parse("content:/path"));
149    assertEquals("Bitmap for content:/path", shadowOf(bitmap).getDescription());
150    assertEquals(123, bitmap.getWidth());
151    assertEquals(456, bitmap.getHeight());
152  }
153
154  @Test
155  public void decodeFileDescriptor_shouldGetWidthAndHeightFromHints() throws Exception {
156    File tmpFile = File.createTempFile("BitmapFactoryTest", null);
157    try {
158      tmpFile.deleteOnExit();
159      FileInputStream is = new FileInputStream(tmpFile);
160      try {
161        FileDescriptor fd = is.getFD();
162        ShadowBitmapFactory.provideWidthAndHeightHints(fd, 123, 456);
163
164        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd);
165        assertEquals("Bitmap for fd:" + fd, shadowOf(bitmap).getDescription());
166        assertEquals(123, bitmap.getWidth());
167        assertEquals(456, bitmap.getHeight());
168      } finally {
169        is.close();
170      }
171    } finally {
172      tmpFile.delete();
173    }
174  }
175
176  @Test
177  public void decodeByteArray_shouldGetWidthAndHeightFromHints() throws Exception {
178    String data = "arbitrary bytes";
179    ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse(data), 123, 456);
180
181    byte[] bytes = data.getBytes(UTF_8);
182    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
183    assertEquals("Bitmap for " + data, shadowOf(bitmap).getDescription());
184    assertEquals(123, bitmap.getWidth());
185    assertEquals(456, bitmap.getHeight());
186  }
187
188  @Test
189  public void decodeByteArray_shouldIncludeOffsets() throws Exception {
190    String data = "arbitrary bytes";
191    ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse(data), 123, 456);
192
193    byte[] bytes = data.getBytes(UTF_8);
194    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 1, bytes.length - 2);
195    assertEquals("Bitmap for " + data + " bytes 1..13", shadowOf(bitmap).getDescription());
196  }
197
198  @Test
199  public void decodeStream_shouldGetWidthAndHeightFromHints() throws Exception {
200    ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse("content:/path"), 123, 456);
201
202    InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path"));
203    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
204    assertEquals("Bitmap for content:/path", shadowOf(bitmap).getDescription());
205    assertEquals(123, bitmap.getWidth());
206    assertEquals(456, bitmap.getHeight());
207  }
208
209  @Test
210  public void decodeStream_shouldGetWidthAndHeightFromActualImage() throws Exception {
211    InputStream inputStream = getClass().getClassLoader().getResourceAsStream("res/drawable/fourth_image.jpg");
212    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
213    assertEquals("Bitmap", shadowOf(bitmap).getDescription());
214    assertEquals(160, bitmap.getWidth());
215    assertEquals(107, bitmap.getHeight());
216  }
217
218  @Test
219  public void decodeByteArray_shouldSetDataChecksum() throws Exception {
220    byte[] data = {23, -125, 0, 52, 23, 18, 76, 43};
221
222    Bitmap bitmap = ShadowBitmapFactory.decodeByteArray(data, 0, data.length);
223    assertThat(bitmap).isNotNull();
224    assertThat(shadowOf(bitmap).getDescription()).isEqualTo("Bitmap for byte array, checksum: 3693078531");
225    assertThat(bitmap.getWidth()).isEqualTo(100);
226    assertThat(bitmap.getHeight()).isEqualTo(100);
227  }
228
229  @Test
230  public void decodeByteArray_withOptionsShouldSetDataChecksum() throws Exception {
231    byte[] data = {23, -125, 0, 52, 23, 18, 76, 43};
232
233    BitmapFactory.Options options = new BitmapFactory.Options();
234    options.inSampleSize = 4;
235    Bitmap bitmap = ShadowBitmapFactory.decodeByteArray(data, 0, data.length - 1, options);
236    assertThat(shadowOf(bitmap).getDescription()).isEqualTo("Bitmap for byte array, checksum: 3693078531 bytes 0..7 with options inSampleSize=4");
237    assertThat(bitmap.getWidth()).isEqualTo(25);
238    assertThat(bitmap.getHeight()).isEqualTo(25);
239  }
240
241  @Test
242  public void decodeWithDifferentSampleSize() {
243    String name = "test";
244    BitmapFactory.Options options = new BitmapFactory.Options();
245
246    options.inSampleSize = 0;
247    Bitmap bm = ShadowBitmapFactory.create(name, options);
248    assertThat(bm.getWidth()).isEqualTo(100);
249    assertThat(bm.getHeight()).isEqualTo(100);
250
251    options.inSampleSize = 2;
252    bm = ShadowBitmapFactory.create(name, options);
253    assertThat(bm.getWidth()).isEqualTo(50);
254    assertThat(bm.getHeight()).isEqualTo(50);
255
256    options.inSampleSize = 101;
257    bm = ShadowBitmapFactory.create(name, options);
258    assertThat(bm.getWidth()).isEqualTo(1);
259    assertThat(bm.getHeight()).isEqualTo(1);
260  }
261
262  @Test
263  public void createShouldSetSizeToValueFromMapAsFirstPriority() {
264    ShadowBitmapFactory.provideWidthAndHeightHints("image.png", 111, 222);
265
266    final Bitmap bitmap = ShadowBitmapFactory.create("file:image.png", null, new Point(50, 60));
267
268    assertThat(bitmap.getWidth()).isEqualTo(111);
269    assertThat(bitmap.getHeight()).isEqualTo(222);
270  }
271
272  @Test
273  public void createShouldSetSizeToParameterAsSecondPriority() {
274    final Bitmap bitmap = ShadowBitmapFactory.create(null, null, new Point(70, 80));
275
276    assertThat(bitmap.getWidth()).isEqualTo(70);
277    assertThat(bitmap.getHeight()).isEqualTo(80);
278  }
279
280  @Test
281  public void createShouldSetSizeToHardcodedValueAsLastPriority() {
282    final Bitmap bitmap = ShadowBitmapFactory.create(null, null, null);
283
284    assertThat(bitmap.getWidth()).isEqualTo(100);
285    assertThat(bitmap.getHeight()).isEqualTo(100);
286  }
287}
288