/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.android.builder.png;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.ide.common.internal.AaptCruncher;
import com.android.ide.common.internal.CommandLineRunner;
import com.android.ide.common.internal.LoggedErrorException;
import com.android.ide.common.internal.PngCruncher;
import com.android.sdklib.BuildToolInfo;
import com.android.sdklib.SdkManager;
import com.android.sdklib.repository.FullRevision;
import com.android.utils.ILogger;
import com.android.utils.StdLogger;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.DataFormatException;
/**
* Synchronous version of the aapt cruncher test.
*/
public class NinePatchAaptProcessorTest extends BasePngTest {
static AtomicLong START_TIME = new AtomicLong(System.currentTimeMillis());
public static Test suite() {
sourceAndCrunchedFiles.clear();
TestSuite suite = new TestSuite();
suite.setName("NinePatchAaptProcessor");
NinePatchAaptProcessorTest test = null;
for (File file : getNinePatches()) {
if (test == null) {
START_TIME.set(System.currentTimeMillis());
}
String testName = "process_aapt_" + file.getName();
test = (NinePatchAaptProcessorTest) TestSuite.createTest(
NinePatchAaptProcessorTest.class, testName);
test.setFile(file);
suite.addTest(test);
}
if (test != null) {
test.setIsFinal(true);
}
return suite;
}
@NonNull
private File mFile;
private boolean mIsFinal = false;
protected void setFile(@NonNull File file) {
mFile = file;
}
protected void setIsFinal(boolean isFinal) {
mIsFinal = isFinal;
}
@NonNull
protected File getAapt() {
return getAapt(FullRevision.parseRevision("20"));
}
@NonNull
protected File getAapt(FullRevision fullRevision) {
ILogger logger = new StdLogger(StdLogger.Level.VERBOSE);
SdkManager sdkManager = SdkManager.createManager(getSdkDir().getAbsolutePath(), logger);
assert sdkManager != null;
BuildToolInfo buildToolInfo = sdkManager.getBuildTool(fullRevision);
if (buildToolInfo == null) {
throw new RuntimeException("Test requires build-tools 20");
}
return new File(buildToolInfo.getPath(BuildToolInfo.PathId.AAPT));
}
@NonNull
protected PngCruncher getCruncher() {
ILogger logger = new StdLogger(StdLogger.Level.VERBOSE);
CommandLineRunner commandLineRunner = new CommandLineRunner(logger);
File aapt = getAapt();
return new AaptCruncher(aapt.getAbsolutePath(), commandLineRunner);
}
private static Map<File, File> sourceAndCrunchedFiles = new HashMap<File, File>();
public void tearSuiteDown() throws IOException, DataFormatException {
long startTime = System.currentTimeMillis();
try {
getCruncher().end();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("waiting for requests completion : " + (System.currentTimeMillis() - startTime));
System.out.println("total time : " + (System.currentTimeMillis() - START_TIME.get()));
System.out.println("Comparing crunched files");
long comparisonStartTime = System.currentTimeMillis();
for (Map.Entry<File, File> sourceAndCrunched : sourceAndCrunchedFiles.entrySet()) {
System.out.println(sourceAndCrunched.getKey().getName());
File crunched = new File(sourceAndCrunched.getKey().getParent(), sourceAndCrunched.getKey().getName() + getControlFileSuffix());
//copyFile(sourceAndCrunched.getValue(), crunched);
Map<String, Chunk> testedChunks = compareChunks(crunched, sourceAndCrunched.getValue());
try {
compareImageContent(crunched, sourceAndCrunched.getValue(), false);
} catch(Throwable e) {
throw new RuntimeException("Failed with " + testedChunks.get("IHDR"), e);
}
}
System.out.println("Done comparing crunched files " + (System.currentTimeMillis() - comparisonStartTime));
}
protected String getControlFileSuffix() {
return ".crunched.aapt";
}
private static void copyFile(File source, File dest)
throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
inputChannel.close();
outputChannel.close();
}
}
@NonNull
protected File crunchFile(@NonNull File file)
throws IOException, NinePatchException, DataFormatException, InterruptedException,
LoggedErrorException {
File outFile = File.createTempFile("pngWriterTest", ".png");
outFile.deleteOnExit();
PngCruncher aaptCruncher = getCruncher();
try {
aaptCruncher.crunchPng(file, outFile);
} catch (InterruptedException e) {
e.printStackTrace();
throw e;
} catch (LoggedErrorException e) {
e.printStackTrace();
throw e;
}
return outFile;
}
@Override
protected void runTest() throws Throwable {
File outFile = crunchFile(mFile);
sourceAndCrunchedFiles.put(mFile, outFile);
if (mIsFinal) {
tearSuiteDown();
}
}
private static Map<String, Chunk> compareChunks(@NonNull File original, @NonNull File tested) throws
IOException, DataFormatException {
Map<String, Chunk> originalChunks = readChunks(original);
Map<String, Chunk> testedChunks = readChunks(tested);
compareChunk(originalChunks, testedChunks, "IHDR");
compareChunk(originalChunks, testedChunks, "npLb");
compareChunk(originalChunks, testedChunks, "npTc");
return testedChunks;
}
private static void compareChunk(
@NonNull Map<String, Chunk> originalChunks,
@NonNull Map<String, Chunk> testedChunks,
@NonNull String chunkType) {
assertEquals(originalChunks.get(chunkType), testedChunks.get(chunkType));
}
@NonNull
protected static File[] getNinePatches() {
File pngFolder = getPngFolder();
File ninePatchFolder = new File(pngFolder, "ninepatch");
File[] files = ninePatchFolder.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.getPath().endsWith(SdkConstants.DOT_9PNG);
}
});
if (files != null) {
return files;
}
return new File[0];
}
}