/* * Copyright 2008 Google 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.google.gwt.user.rebind.ui; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.dev.util.UnitTestTreeLogger; import com.google.gwt.user.client.ui.ImageBundle.Resource; import com.google.gwt.user.rebind.ui.ImageBundleBuilder.HasRect; import com.google.gwt.user.rebind.ui.ImageBundleGenerator.JMethodOracle; import junit.framework.TestCase; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Unit tests for {@link ImageBundleGenerator}. Note that, at present, only a * small minority of the functionality is really covered. The present tests * cover the correctness of compile-time diagnostics and the sequence and * phrasing of error and warning log messages. */ public class ImageBundleGeneratorTest extends TestCase { private static class MockRect implements HasRect { private final String name; private final int width, height; private int left, top; private boolean hasBeenPositioned; MockRect(String name, int width, int height) { this.name = name; this.width = width; this.height = height; } public int getHeight() { return height; } public int getLeft() { return left; } public String getName() { return name; } public int getTop() { return top; } public int getWidth() { return width; } public boolean hasBeenPositioned() { return hasBeenPositioned; } public void setPosition(int left, int top) { this.left = left; this.top = top; hasBeenPositioned = true; } @Override public String toString() { return "{" + left + ", " + top + ", " + width + ", " + height + "}"; } void assertPosition(int left, int top) { assertTrue(hasBeenPositioned); assertEquals(left, this.left); assertEquals(top, this.top); } MockRect duplicate() { final MockRect mr = new MockRect(name, width, height); mr.hasBeenPositioned = hasBeenPositioned; mr.left = left; mr.top = top; return mr; } } /** * Ensures that two collections of MockRects are arranged identically. * * @param a first collection * @param b second collection */ private static void assertSameArrangement(Collection<MockRect> a, Collection<MockRect> b) { final Map<String, MockRect> index = new HashMap<String, MockRect>(); for (MockRect r : a) { index.put(r.getName(), r); } for (MockRect rb : b) { final MockRect ra = index.get(rb.getName()); rb.assertPosition(ra.getLeft(), ra.getTop()); } } @Resource("dunebuggy.gif") public void duneBuggyInDefaultPackage() { } @Resource("a/b/c/dunebuggy.gif") public void duneBuggyInNonDefaultPackage() { } @Resource("io.jpg") public void ioInSamePackage() { } /** * Validates that presenting the images in different orders does not affect * the arrangement. */ public void testArrangementIsDeterministic() { List<MockRect> orderA = Arrays.asList(new MockRect("a", 50, 100), new MockRect("b", 50, 100), new MockRect("c", 100, 50), new MockRect( "d", 50, 50), new MockRect("e", 50, 50)); List<MockRect> orderB = new ArrayList<MockRect>(); for (int i = orderA.size() - 1; i <= 0; --i) { orderB.add(orderA.get(i)); } ImageBundleBuilder.arrangeImages(orderA); ImageBundleBuilder.arrangeImages(orderB); assertSameArrangement(orderA, orderB); } /** * Ensures that the basic image packing algorithm is arranging images as * expected. */ public void testBasicImageArrangement() { // Expected in 2nd column, 2nd in 2nd row. final MockRect ra = new MockRect("a", 20, 30); // Expected to be 1st column. final MockRect rb = new MockRect("b", 10, 100); // Expected in 2nd column, 1st in 2nd row. final MockRect rc = new MockRect("c", 20, 40); // Expected in 2nd column, it is the 1st row. final MockRect rd = new MockRect("d", 100, 60); // Expected in 2nd column, 3rd in 2nd row. final MockRect re = new MockRect("e", 10, 30); final Collection<MockRect> rects = new ArrayList<MockRect>(); Collections.addAll(rects, ra, rb, rc, rd, re); ImageBundleBuilder.arrangeImages(rects); ra.assertPosition(30, 60); rb.assertPosition(0, 0); rc.assertPosition(10, 60); rd.assertPosition(10, 0); re.assertPosition(50, 60); } /** * This method is to remind the reader that ClassLoader.getResource() doesn't * want a leading "/" on resource names. */ public void testClassLoaderGetResourceHatesLeadingSlash() { String fqcn = getClass().getCanonicalName(); // This class has a name. assertNotNull(fqcn); String thisClassResName = fqcn.replace('.', '/') + ".class"; // It has some slashes. assertTrue(thisClassResName.indexOf('/') >= 0); // But it does not start with a slash. assertFalse(thisClassResName.startsWith("/")); // The resource is successfully found without a leading slash. URL url = getClass().getClassLoader().getResource(thisClassResName); assertNotNull(url); // It fails to be found found with a leading slash. url = getClass().getClassLoader().getResource("/" + thisClassResName); assertNull(url); } /** * Tests that a message is logged and an exception is thrown when a resource * isn't found after being sought based on the ImageBundle.Resource * annotation. */ @Resource("notfound.png") public void testResourceNotFoundGivenAnnotation() { UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder(); b.expectError( ImageBundleGenerator.msgCannotFindImageFromMetaData("from/metadata/notfound.png"), null); UnitTestTreeLogger logger = b.createLogger(); try { getImageName(logger, new String[0], "nonexistentImg", "from.metadata", getResourceAnnotation("testResourceNotFoundGivenAnnotation")); fail("Should have thrown"); } catch (UnableToCompleteException e) { } logger.assertCorrectLogEntries(); } /** * Tests that a message is logged and an exception is thrown when a resource * isn't found after being sought based on the method name. */ public void testResourceNotFoundGivenNoMetaData() { UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder(); b.expectError(ImageBundleGenerator.MSG_NO_FILE_BASED_ON_METHOD_NAME, null); b.expectError("test/nonexistentImg.png", null); b.expectError("test/nonexistentImg.gif", null); b.expectError("test/nonexistentImg.jpg", null); UnitTestTreeLogger logger = b.createLogger(); try { getImageName(logger, new String[0], "nonexistentImg", "test", null); fail("Should have thrown"); } catch (UnableToCompleteException e) { } logger.assertCorrectLogEntries(); } /** * Tests that resources can be found in a variety of ways from an image bundle * residing in the default package. */ public void testResourcesFoundFromImageBundleInDefaultPackage() throws UnableToCompleteException { UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder(); UnitTestTreeLogger logger = b.createLogger(); { // [1] Find an image in the default package using the method name. String imgName = getImageName(logger, new String[] { "cabbage.jpg", "lettuce.jpg",}, "cabbage", "", null); assertEquals("cabbage.jpg", imgName); } { // [2] Find an image in the default package using an annotation. String imgName = getImageName(logger, new String[] { "car.png", "dunebuggy.gif",}, "vehicleImage", "", getResourceAnnotation("duneBuggyInDefaultPackage")); assertEquals("dunebuggy.gif", imgName); } { // [3] Find an image in a non-default package using an annotation. String imgName = getImageName(logger, new String[] { "car.png", "dunebuggy.gif", "a/b/c/dunebuggy.gif",}, "vehicleImage", "", getResourceAnnotation("duneBuggyInNonDefaultPackage")); assertEquals("a/b/c/dunebuggy.gif", imgName); } logger.assertCorrectLogEntries(); } /** * Tests that resources can be found in a variety of ways from an image bundle * residing in a non-default package. */ public void testResourcesFoundFromImageBundleInNonDefaultPackage() throws UnableToCompleteException { UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder(); UnitTestTreeLogger logger = b.createLogger(); { // [1] Find an image in the same package using the method name. String imgName = getImageName(logger, new String[] { "x/y/z/europa.png", "x/y/z/io.jpg",}, "io", "x.y.z", null); assertEquals("x/y/z/io.jpg", imgName); } { // [2] Find an image in the same package using an annotation. String imgName = getImageName(logger, new String[] { "x/y/z/europa.png", "x/y/z/io.jpg",}, "moonImage", "x.y.z", getResourceAnnotation("ioInSamePackage")); assertEquals("x/y/z/io.jpg", imgName); } { // [3] Find an image in a non-default package using an annotation. String imgName = getImageName(logger, new String[] { "car.png", "dunebuggy.gif", "a/b/c/dunebuggy.gif",}, "vehicleImage", "x.y.z", getResourceAnnotation("duneBuggyInNonDefaultPackage")); assertEquals("a/b/c/dunebuggy.gif", imgName); } logger.assertCorrectLogEntries(); } private JMethodOracle createJMethodOracle(final String methodName, final String packageName, final Resource resourceAnnotation) { return new JMethodOracle() { public Resource getAnnotation(Class<Resource> clazz) { return resourceAnnotation; } public String getName() { return methodName; } public String getPackageName() { return packageName; } }; } private String getImageName(UnitTestTreeLogger logger, final String[] pretendResources, String methodName, String pkgName, final Resource resAnn) throws UnableToCompleteException { ImageBundleGenerator ibg = new ImageBundleGenerator( new ImageBundleGenerator.ResourceLocator() { private final List<String> resList = Arrays.asList(pretendResources); public boolean isResourcePresent(String resName) { return resList.contains(resName); } }); JMethodOracle methodOracle = createJMethodOracle(methodName, pkgName, resAnn); return ibg.getImageResourceName(logger, methodOracle); } private Resource getResourceAnnotation(String methodName) { Throwable caught = null; try { Resource res = getClass().getMethod(methodName, new Class[0]).getAnnotation( Resource.class); assertNotNull(res); return res; } catch (SecurityException e) { caught = e; } catch (NoSuchMethodException e) { caught = e; } fail("Unable to get @Resource annotation from method '" + methodName + "' during test due to exception: " + caught.getMessage()); return null; } }