1   package com.atlassian.core.util.thumbnail;
2   
3   import com.atlassian.core.util.ImageInfo;
4   import junit.framework.TestCase;
5   
6   import java.awt.*;
7   import java.awt.image.BufferedImage;
8   import java.io.File;
9   import java.io.FileInputStream;
10  import java.io.IOException;
11  import javax.imageio.ImageIO;
12  
13  /**
14   * This tests vary on the level of abstraction tested.
15   * The reason is that I did not want to change public interface (method visibility) of Thumber class (in order to
16   * keep clients compatible).
17   * Thus sometimes higher level methods are tested and the test are not really unit -> e.g. testing
18   * {@link com.atlassian.core.util.thumbnail.Thumber#retrieveOrCreateThumbNail(java.io.InputStream, String, java.io.File, int, int, long)}
19   */
20  public class ThumberTest extends TestCase
21  {
22      private static final int MAX_WIDTH = 30;
23      private static final int MAX_HEIGHT = 40;
24      private final File tempFile;
25      private static final String TEST_FILE_NAME = "mypicture.png";
26  
27      public ThumberTest() throws IOException
28      {
29          tempFile = File.createTempFile("atlassian-core-thumbnail", "test");
30      }
31  
32      @Override
33      protected void setUp() throws Exception
34      {
35          //noinspection ResultOfMethodCallIgnored
36          tempFile.delete(); // this file must not exist, other wise thumber won't try to scale the image
37      }
38  
39      @Override
40      protected void tearDown() throws Exception
41      {
42          //noinspection ResultOfMethodCallIgnored
43          tempFile.delete();
44      }
45  
46      public void testRetrieveOrCreateThumbnailTransparentPng() throws IOException
47      {
48          Thumber thumber = new Thumber(Thumbnail.MimeType.PNG);
49          testRetrieveOrCreateThumbnail(thumber, "/transparent-png.png", Transparency.TRANSLUCENT, ImageInfo.FORMAT_PNG);
50      }
51  
52      public void testRetrieveOrCreateThumbnailOpaqueGif() throws IOException
53      {
54          Thumber thumber = new Thumber();
55          testRetrieveOrCreateThumbnail(thumber, "/opaque-gif.gif", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
56      }
57  
58  
59      public void testRetrieveOrCreateThumbnailOpaquePng() throws IOException
60      {
61          Thumber thumber = new Thumber();
62          testRetrieveOrCreateThumbnail(thumber, "/opaque-png.png", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
63      }
64  
65      public void testRetrieveOrCreateThumbnailJpg() throws IOException
66      {
67          Thumber thumber = new Thumber();
68          testRetrieveOrCreateThumbnail(thumber, "/test-jpg.jpg", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
69      }
70  
71      public void testRetrieveOrCreateThumbnailTransparentGif() throws IOException
72      {
73          Thumber thumber = new Thumber(Thumbnail.MimeType.PNG);
74          testRetrieveOrCreateThumbnail(thumber, "/transparent-gif.gif", Transparency.TRANSLUCENT, ImageInfo.FORMAT_PNG);
75      }
76  
77  
78      public void testScaleImageForNonBufferedImage()
79      {
80          // this should normally produce ToolkitImage
81          final Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/opaque-gif.gif"));
82          final BufferedImage thumbnail = new Thumber().scaleImage(image,
83                  new Thumber.WidthHeightHelper(MAX_WIDTH, MAX_HEIGHT));
84  
85          // scaleImage ignores aspect ratio -> always produces desired with & height
86          assertEquals(MAX_WIDTH, thumbnail.getWidth());
87          assertEquals(MAX_HEIGHT, thumbnail.getHeight());
88          assertEquals(Transparency.OPAQUE, thumbnail.getTransparency());
89      }
90  
91      public void testScaleImageForNonBufferedImageTransparentGif()
92      {
93          // this should normally produce ToolkitImage
94          final Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/transparent-gif.gif"));
95          final BufferedImage thumbnail = new Thumber().scaleImage(image,
96                  new Thumber.WidthHeightHelper(MAX_WIDTH, MAX_HEIGHT));
97  
98          // scaleImage ignores aspect ratio -> always produces desired with & height
99          assertEquals(MAX_WIDTH, thumbnail.getWidth());
100         assertEquals(MAX_HEIGHT, thumbnail.getHeight());
101         assertEquals(Transparency.TRANSLUCENT, thumbnail.getTransparency());
102     }
103 
104     public void testUpscalingShouldReturnOriginalSize() throws IOException
105     {
106         final String resourceName = "/opaque-png.png";
107         final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(resourceName));
108         final int width = image.getWidth();
109         final int height = image.getHeight();
110         final Thumbnail thumbnail = new Thumber().retrieveOrCreateThumbNail(
111                 getClass().getResourceAsStream(resourceName), TEST_FILE_NAME,
112                 tempFile, width * 3, height * 3, 1);
113 
114         assertThumbnail(thumbnail, Transparency.OPAQUE, ImageInfo.FORMAT_JPEG, width, height);
115     }
116 
117     public void testScaleImageUpscaling() throws IOException
118     {
119         final String resourceName = "/opaque-png.png";
120         final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(resourceName));
121         final int width = image.getWidth();
122         final int height = image.getHeight();
123         assertScaleImage(image, width * 3, height * 3);
124         assertScaleImage(image, width - 10, height + 100);
125         assertScaleImage(image, width + 100, height - 20);
126     }
127 
128     public void testScaleImageWithInvalidParams() throws IOException
129     {
130         final String resourceName = "/opaque-png.png";
131         final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(resourceName));
132         try
133         {
134             assertScaleImage(image, -30, -20);
135             fail(IllegalArgumentException.class.getName() + " expected");
136         }
137         catch (IllegalArgumentException ignore)
138         {
139             // this is expected
140         }
141     }
142 
143     /**
144      * Testing extremely wide and tall images clamp minimum width and height to 1,
145      * as per http://jira.atlassian.com/browse/JRA-20369
146      */
147     public void testDetermineScaleSize() throws Exception {
148         Thumber t = new Thumber();
149         Thumber.WidthHeightHelper helper = t.determineScaleSize(20, 20, 1, 600);
150         assertEquals(1, helper.getWidth());
151         assertEquals(20, helper.getHeight());
152 
153         helper = t.determineScaleSize(200, 200, 600, 1);
154         assertEquals(200, helper.getWidth());
155         assertEquals(1, helper.getHeight());
156     }
157 
158     private void assertScaleImage(final BufferedImage image, int aWidth, int aHeight)
159     {
160         final BufferedImage thumbnail = new Thumber().scaleImage(image, new Thumber.WidthHeightHelper(aWidth,
161                 aHeight));
162         assertEquals(aWidth, thumbnail.getWidth());
163         assertEquals(aHeight, thumbnail.getHeight());
164         assertEquals(image.getTransparency(), thumbnail.getTransparency());
165     }
166 
167     private void testRetrieveOrCreateThumbnail(Thumber thumber, String imageResourceName, int expectedTransparency, int expectedFormat) throws IOException
168     {
169         final Thumbnail thumbnail = thumber.retrieveOrCreateThumbNail(
170                 getClass().getResourceAsStream(imageResourceName), TEST_FILE_NAME,
171                 tempFile, MAX_WIDTH, MAX_HEIGHT, 1);
172 
173         final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(imageResourceName));
174 
175         assertThumbnail(thumbnail, expectedTransparency, expectedFormat,
176                 MAX_WIDTH, MAX_WIDTH * image.getHeight() / image.getWidth());
177     }
178 
179     private void assertThumbnail(final Thumbnail thumbnail, final int expectedTransparency, final int expectedFormat,
180             int expectedWidth, int expectedHeight) throws IOException
181     {
182         assertEquals(expectedWidth, thumbnail.getWidth());
183         assertEquals(expectedHeight, thumbnail.getHeight());
184         assertEquals(TEST_FILE_NAME, thumbnail.getFilename());
185 
186         final BufferedImage thumbnailImage = ImageIO.read(tempFile);
187         assertEquals(expectedWidth, thumbnailImage.getWidth());
188         assertEquals(expectedHeight, thumbnailImage.getHeight());
189         assertEquals(expectedTransparency, thumbnailImage.getTransparency());
190         assertImageType(tempFile, expectedFormat);
191     }
192 
193 
194     private void assertImageType(final File tempFile, int format) throws IOException
195     {
196         final ImageInfo imageInfo = new ImageInfo();
197         final FileInputStream fis = new FileInputStream(tempFile);
198         imageInfo.setInput(fis);
199         assertTrue(imageInfo.check());
200         assertEquals(format, imageInfo.getFormat());
201         fis.close();
202     }
203 }