/*
* IconManagerTest.java 4 mai 2006
*
* Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights
* Reserved.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.junit;
import java.awt.Component;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Arrays;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import junit.framework.TestCase;
import com.eteks.sweethome3d.model.Content;
import com.eteks.sweethome3d.swing.IconManager;
import com.eteks.sweethome3d.tools.URLContent;
/**
* Tests IconManager class.
* @author Emmanuel Puybaret
*/
public class IconManagerTest extends TestCase {
private final int HEIGHT = 32;
public void testIconManager()
throws NoSuchFieldException, IllegalAccessException, InterruptedException, BrokenBarrierException, ClassNotFoundException {
// Stop iconsLoader of iconManager
IconManager iconManager = IconManager.getInstance();
iconManager.clear();
// Replace icon manager by an executor that controls the start of a task with a barrier
final CyclicBarrier iconLoadingStartBarrier = new CyclicBarrier(2);
final ThreadPoolExecutor replacingIconsLoader =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) {
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
awaitBarrier(iconLoadingStartBarrier);
}
};
// Redirect rejected tasks on iconsLoader to the replacing executor
TestUtilities.setField(iconManager, "iconsLoader", replacingIconsLoader);
// Test icon loading on a good image
testIconLoading(getClass().getResource("resources/test.png"), true, iconLoadingStartBarrier);
// Test icon loading on a content that doesn't an image
testIconLoading(getClass().getResource("IconManagerTest.class"), false, iconLoadingStartBarrier);
Class iconProxyClass = Class.forName(iconManager.getClass().getName() + "$IconProxy");
URLContent waitIconContent =
(URLContent)TestUtilities.getField(iconManager, "waitIconContent");
URLContent errorIconContent =
(URLContent)TestUtilities.getField(iconManager, "errorIconContent");
// Check waitIcon is loaded directly without proxy
Icon waitIcon = iconManager.getIcon(waitIconContent, HEIGHT, null);
assertNotSame("Wait icon loaded with IconProxy", waitIcon.getClass(), iconProxyClass);
// Check errorIcon is loaded directly without proxy
Icon errorIcon = iconManager.getIcon(errorIconContent, HEIGHT, null);
assertNotSame("Error icon loaded with IconProxy", errorIcon.getClass(), iconProxyClass);
// For other tests, replace again iconLoader by an executor that let icon loading complete normally
iconManager.clear();
}
/**
* Test how an icon is loaded by IconManager.
*/
private void testIconLoading(URL iconURL, boolean goodIcon, CyclicBarrier iconLoadingStartBarrier)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InterruptedException, BrokenBarrierException {
IconManager iconManager = IconManager.getInstance();
Class iconProxyClass = Class.forName(iconManager.getClass().getName() + "$IconProxy");
URLContent waitIconContent =
(URLContent)TestUtilities.getField(iconManager, "waitIconContent");
URLContent errorIconContent =
(URLContent)TestUtilities.getField(iconManager, "errorIconContent");
final CyclicBarrier waitingComponentBarrier = new CyclicBarrier(2);
// A dummy waiting component that waits on a barrier in its repaint method
Component waitingComponent = new Component() {
public void repaint() {
awaitBarrier(waitingComponentBarrier);
}
};
Content iconContent = new URLContent(iconURL);
Icon icon = iconManager.getIcon(iconContent, HEIGHT, waitingComponent);
assertEquals("Icon not equal to wait icon while loading", waitIconContent.getURL(), icon);
// Let iconManager load the iconContent
iconLoadingStartBarrier.await();
// Wait iconContent loading completion
waitingComponentBarrier.await();
if (goodIcon) {
assertEquals("Icon not equal to icon read from resource", iconURL, icon);
} else {
assertEquals("Wrong icon not equal to errorIcon", errorIconContent.getURL(), icon);
}
// Check icon is loaded with proxy
assertSame("Icon not loaded with IconProxy", icon.getClass(), iconProxyClass);
// Check that icon is stored in cache
Icon iconFromCache = iconManager.getIcon(iconContent, HEIGHT, waitingComponent);
assertSame("Test icon reloaded", icon, iconFromCache);
}
private void awaitBarrier(CyclicBarrier barrier) {
try {
barrier.await();
} catch (Exception ex) {
fail();
}
}
/**
* Asserts icons in parameter at same size contains the same image data.
*/
private void assertEquals(String message, URL expectedIconURL, Icon actualIcon) {
ImageIcon expectedIcon = new ImageIcon(expectedIconURL);
Image scaledExpectedImage = expectedIcon.getImage()
.getScaledInstance(actualIcon.getIconWidth(),
actualIcon.getIconHeight(), Image.SCALE_SMOOTH);
assertTrue(message, Arrays.equals(getIconData(new ImageIcon(scaledExpectedImage)),
getIconData(actualIcon)));
}
private int [] getIconData(Icon icon) {
BufferedImage image = new BufferedImage(icon.getIconWidth(),
icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
icon.paintIcon(null, image.getGraphics(), 0, 0);
int [] imageData = new int [icon.getIconWidth() * icon.getIconHeight()];
return image.getRGB(0, 0, icon.getIconWidth(), icon.getIconHeight(),
imageData, 0, icon.getIconWidth());
}
}