blob: c74d0ecfb1159153f6582c9302588cf7849a7503 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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.android.assetstudiolib;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import junit.framework.TestCase;
/**
* Shared test infrastructure for code generator
*/
public abstract class GeneratorTest extends TestCase implements GraphicGeneratorContext {
private static final String TEST_DATA_REL_PATH =
"assetstudio/tests/src/com/android/assetstudiolib/testdata";
protected void checkGraphic(int expectedFileCount, String folderName, String baseName,
GraphicGenerator generator, GraphicGenerator.Options options)
throws IOException {
Map<String, Map<String, BufferedImage>> categoryMap =
new HashMap<String, Map<String, BufferedImage>>();
options.sourceImage = GraphicGenerator.getClipartImage("android.png");
generator.generate(null, categoryMap, this, options, baseName);
File targetDir = getTargetDir();
List<String> errors = new ArrayList<String>();
int fileCount = 0;
for (Map<String, BufferedImage> previews : categoryMap.values()) {
for (Map.Entry<String, BufferedImage> entry : previews.entrySet()) {
String relativePath = entry.getKey();
BufferedImage image = entry.getValue();
if (image == null) continue;
String path = "testdata" + File.separator + folderName + File.separator
+ relativePath;
InputStream is = GeneratorTest.class.getResourceAsStream(path);
if (is == null) {
if (targetDir == null) {
fail("Did not find " + path
+ ". Set ADT_SDK_SOURCE_PATH to have it created automatically");
}
File fileName = new File(targetDir, folderName + File.separator
+ relativePath);
assertFalse(fileName.exists());
if (!fileName.getParentFile().exists()) {
boolean mkdir = fileName.getParentFile().mkdirs();
assertTrue(fileName.getParent(), mkdir);
}
ImageIO.write(image, "PNG", fileName);
errors.add("File did not exist, created " + fileName.getPath());
} else {
BufferedImage goldenImage = ImageIO.read(is);
assertImageSimilar(relativePath, goldenImage, image, 5.0f);
}
}
fileCount += previews.values().size();
}
if (errors.size() > 0) {
fail(errors.toString());
}
assertEquals("Wrong number of generated files", expectedFileCount, fileCount);
}
public static void assertImageSimilar(String imageName, BufferedImage goldenImage,
BufferedImage image, float maxPercentDifferent) throws IOException {
assertTrue("Widths differ too much for " + imageName, Math.abs(goldenImage.getWidth()
- image.getWidth()) < 2);
assertTrue("Widths differ too much for " + imageName, Math.abs(goldenImage.getHeight()
- image.getHeight()) < 2);
assertEquals(BufferedImage.TYPE_INT_ARGB, image.getType());
if (goldenImage.getType() != BufferedImage.TYPE_INT_ARGB) {
BufferedImage temp = new BufferedImage(goldenImage.getWidth(), goldenImage.getHeight(),
BufferedImage.TYPE_INT_ARGB);
temp.getGraphics().drawImage(goldenImage, 0, 0, null);
goldenImage = temp;
}
assertEquals(BufferedImage.TYPE_INT_ARGB, goldenImage.getType());
int imageWidth = Math.min(goldenImage.getWidth(), image.getWidth());
int imageHeight = Math.min(goldenImage.getHeight(), image.getHeight());
// Blur the images to account for the scenarios where there are pixel
// differences
// in where a sharp edge occurs
// goldenImage = blur(goldenImage, 6);
// image = blur(image, 6);
int width = 3 * imageWidth;
int height = imageHeight;
BufferedImage deltaImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = deltaImage.getGraphics();
// Compute delta map
long delta = 0;
for (int y = 0; y < imageHeight; y++) {
for (int x = 0; x < imageWidth; x++) {
int goldenRgb = goldenImage.getRGB(x, y);
int rgb = image.getRGB(x, y);
if (goldenRgb == rgb) {
deltaImage.setRGB(imageWidth + x, y, 0x00808080);
continue;
}
// If the pixels have no opacity, don't delta colors at all
if (((goldenRgb & 0xFF000000) == 0) && (rgb & 0xFF000000) == 0) {
deltaImage.setRGB(imageWidth + x, y, 0x00808080);
continue;
}
int deltaR = ((rgb & 0xFF0000) >>> 16) - ((goldenRgb & 0xFF0000) >>> 16);
int newR = 128 + deltaR & 0xFF;
int deltaG = ((rgb & 0x00FF00) >>> 8) - ((goldenRgb & 0x00FF00) >>> 8);
int newG = 128 + deltaG & 0xFF;
int deltaB = (rgb & 0x0000FF) - (goldenRgb & 0x0000FF);
int newB = 128 + deltaB & 0xFF;
int avgAlpha = ((((goldenRgb & 0xFF000000) >>> 24)
+ ((rgb & 0xFF000000) >>> 24)) / 2) << 24;
int newRGB = avgAlpha | newR << 16 | newG << 8 | newB;
deltaImage.setRGB(imageWidth + x, y, newRGB);
delta += Math.abs(deltaR);
delta += Math.abs(deltaG);
delta += Math.abs(deltaB);
}
}
// 3 different colors, 256 color levels
long total = imageHeight * imageWidth * 3L * 256L;
float percentDifference = (float) (delta * 100 / (double) total);
if (percentDifference > maxPercentDifferent) {
// Expected on the left
// Golden on the right
g.drawImage(goldenImage, 0, 0, null);
g.drawImage(image, 2 * imageWidth, 0, null);
// Labels
if (imageWidth > 80) {
g.setColor(Color.RED);
g.drawString("Expected", 10, 20);
g.drawString("Actual", 2 * imageWidth + 10, 20);
}
File output = new File(getTempDir(), "delta-"
+ imageName.replace(File.separatorChar, '_'));
if (output.exists()) {
output.delete();
}
ImageIO.write(deltaImage, "PNG", output);
String message = String.format("Images differ (by %.1f%%) - see details in %s",
percentDifference, output);
System.out.println(message);
fail(message);
}
g.dispose();
}
protected static File getTempDir() {
if (System.getProperty("os.name").equals("Mac OS X")) {
return new File("/tmp"); //$NON-NLS-1$
}
return new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
}
@Override
public BufferedImage loadImageResource(String path) {
try {
return GraphicGenerator.getStencilImage(path);
} catch (IOException e) {
fail(e.toString());
}
return null;
}
/** Get the location to write missing golden files to */
protected File getTargetDir() {
// Set $ADT_SDK_SOURCE_PATH to point to your git "sdk" directory
String sdk = System.getenv("ADT_SDK_SOURCE_PATH");
if (sdk != null) {
File sdkPath = new File(sdk);
if (sdkPath.exists()) {
File testData = new File(sdkPath, TEST_DATA_REL_PATH.replace('/',
File.separatorChar));
if (testData.exists()) {
return testData;
}
}
}
return null;
}
}