/*
* Copyright (C) 2013 RoboVM AB
*
* 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, see <http://www.gnu.org/licenses/gpl-2.0.html>.
*/
package org.robovm.compiler.config;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.Arrays;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.robovm.compiler.config.Config.Builder;
import org.robovm.compiler.config.Config.Home;
import org.robovm.compiler.config.Config.Lib;
import org.robovm.compiler.target.ConsoleTarget;
import org.robovm.compiler.target.ios.IOSTarget;
import org.zeroturnaround.zip.ZipUtil;
/**
* Tests {@link Config}.
*/
public class ConfigTest {
String savedUserDir;
File tmp;
File wd;
Home fakeHome;
@Before
public void setUp() throws Exception {
savedUserDir = System.getProperty("user.dir");
tmp = new File("/tmp");
wd = new File(tmp, "wd");
System.setProperty("user.dir", wd.getAbsolutePath());
fakeHome = new FakeHome();
}
@After
public void tearDown() {
System.setProperty("user.dir", savedUserDir);
}
@Test
public void testReadConsole() throws Exception {
Config.Builder builder = new Config.Builder();
builder.read(new InputStreamReader(getClass().getResourceAsStream("ConfigTest.console.xml"), "utf-8"), wd);
Config config = builder.config;
assertEquals(Arrays.asList(new File(wd, "foo1.jar"), new File(tmp, "foo2.jar")), config.getClasspath());
assertEquals(Arrays.asList("Foundation", "AppKit"), config.getFrameworks());
assertEquals(Arrays.asList(
new Config.Lib("dl", true),
new Config.Lib("/tmp/wd/libs/libmy.a", true),
new Config.Lib("/tmp/wd/libs/foo.o", true),
new Config.Lib("/usr/lib/libbar.a", false)
), config.getLibs());
assertEquals(Arrays.asList(
new Resource(new File(wd, "resources")),
new Resource(new File("/usr/share/resources")),
new Resource(null, null).include("data/**/*"),
new Resource(null, null).include("videos/**/*.avi"),
new Resource(new File(wd, "resources"), "data")
.include("**/*.png")
.exclude("**/foo.png")
.flatten(true)
), config.getResources());
assertEquals(Arrays.asList("javax.**.*"), config.getForceLinkClasses());
assertEquals(OS.macosx, config.getOs());
assertEquals(2, config.getArchs().size());
assertEquals(Arch.x86, config.getArchs().get(0));
assertEquals(Arch.x86_64, config.getArchs().get(1));
}
@Test
public void testReadOldConsole() throws Exception {
Config.Builder builder = new Config.Builder();
builder.read(new InputStreamReader(getClass().getResourceAsStream("ConfigTest.old.console.xml"), "utf-8"), wd);
Config config = builder.config;
assertEquals(Arrays.asList(new File(wd, "foo1.jar"), new File(tmp, "foo2.jar")), config.getClasspath());
assertEquals(Arrays.asList("Foundation", "AppKit"), config.getFrameworks());
assertEquals(Arrays.asList(
new Config.Lib("dl", true),
new Config.Lib("/tmp/wd/libs/libmy.a", true),
new Config.Lib("/tmp/wd/libs/foo.o", true),
new Config.Lib("/usr/lib/libbar.a", false)
), config.getLibs());
assertEquals(Arrays.asList(new Resource(new File("/tmp/wd/resources")),
new Resource(new File("/usr/share/resources"))),
config.getResources());
assertEquals(Arrays.asList("javax.**.*"), config.getForceLinkClasses());
assertEquals(OS.macosx, config.getOs());
assertEquals(1, config.getArchs().size());
assertEquals(Arch.x86, config.getArchs().get(0));
}
@Test
public void testWriteConsole() throws Exception {
Config.Builder builder = new Config.Builder();
builder.addClasspathEntry(new File("foo1.jar"));
builder.addClasspathEntry(new File(tmp, "foo2.jar"));
builder.addFramework("Foundation");
builder.addFramework("AppKit");
builder.addLib(new Config.Lib("dl", true));
builder.addLib(new Config.Lib("libs/libmy.a", true));
builder.addLib(new Config.Lib("libs/foo.o", true));
builder.addLib(new Config.Lib("/usr/lib/libbar.a", false));
builder.addResource(new Resource(new File("/tmp/wd/resources")));
builder.addResource(new Resource(new File("/usr/share/resources")));
builder.addResource(new Resource(new File("/tmp/wd"), null).include("data/**/*"));
builder.addResource(new Resource(null, null).include("videos/**/*.avi"));
builder.addResource(
new Resource(new File("/tmp/wd/resources"), "data")
.include("**/*.png")
.exclude("**/foo.png")
.flatten(true));
builder.addForceLinkClass("javax.**.*");
builder.os(OS.macosx);
builder.archs(Arch.x86, Arch.x86_64);
StringWriter out = new StringWriter();
builder.write(out, wd);
assertEquals(IOUtils.toString(getClass().getResourceAsStream("ConfigTest.console.xml")), out.toString());
}
@Test
public void testReadIOS() throws Exception {
Config.Builder builder = new Config.Builder();
builder.read(new InputStreamReader(getClass().getResourceAsStream("ConfigTest.ios.xml"), "utf-8"), wd);
Config config = builder.config;
assertEquals("6.1", config.getIosSdkVersion());
assertEquals(new File(wd, "Info.plist"), config.getIosInfoPList().getFile());
assertEquals(new File(wd, "entitlements.plist"), config.getIosEntitlementsPList());
}
@Test
public void testWriteIOS() throws Exception {
Config.Builder builder = new Config.Builder();
builder.iosSdkVersion("6.1");
builder.iosInfoPList(new File("Info.plist"));
builder.iosEntitlementsPList(new File("entitlements.plist"));
builder.targetType(IOSTarget.TYPE);
StringWriter out = new StringWriter();
builder.write(out, wd);
assertEquals(IOUtils.toString(getClass().getResourceAsStream("ConfigTest.ios.xml")), out.toString());
}
private File createMergeConfig(File tmpDir, String dir, String id, OS os, Arch arch, boolean jar) throws Exception {
File p = new File(tmpDir, dir);
for (OS os2 : OS.values()) {
for (Arch arch2 : Arch.values()) {
File root = new File(p, "META-INF/robovm/" + os2 + "/" + arch2);
root.mkdirs();
if (!new File(root, "robovm.xml").exists()) {
new Config.Builder().write(new File(root, "robovm.xml"));
}
}
}
File root = new File(p, "META-INF/robovm/" + os + "/" + arch);
new Config.Builder()
.addExportedSymbol(id.toUpperCase() + "*")
.addForceLinkClass("com." + id.toLowerCase() + ".**")
.addFrameworkPath(new File(root, id.toLowerCase() + "/bar"))
.addFramework(id)
.addLib(new Lib(id.toLowerCase(), true))
.addLib(new Lib(new File(root, "lib" + id.toLowerCase() + ".a").getAbsolutePath(), true))
.addResource(new Resource(new File(root, "resources")))
.addWeakFramework("Weak" + id)
.write(new File(root, "robovm.xml"));
if (jar) {
File jarFile = new File(tmpDir, p.getName() + ".jar");
ZipUtil.pack(p, jarFile);
FileUtils.deleteDirectory(p);
return jarFile;
} else {
return p;
}
}
private File createTempDir() throws IOException {
final File tmp = File.createTempFile(getClass().getName(), ".tmp");
tmp.delete();
FileUtils.deleteDirectory(tmp);
tmp.mkdirs();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
FileUtils.deleteDirectory(tmp);
} catch (IOException e) {
}
}
});
return tmp;
}
@Test
public void testMergeConfigsFromClasspath() throws Exception {
File tmpDir = createTempDir();
File cacheDir = new File(tmpDir, "cache");
File p1 = createMergeConfig(tmpDir, "p1", "Foo", OS.macosx, Arch.x86, false);
File p2 = createMergeConfig(tmpDir, "p2", "Wooz", OS.linux, Arch.x86, false);
// Create a jar file with both x86 and x86_64 by first creating a folder for x86 in p3/
// and then passing p3/ again but this time compress it to a jar.
createMergeConfig(tmpDir, "p3", "Baaz", OS.macosx, Arch.x86, false);
File p3 = createMergeConfig(tmpDir, "p3", "Raaz", OS.macosx, Arch.x86_64, true);
Config.Builder builder = new Config.Builder();
builder.cacheDir(cacheDir);
builder.os(OS.macosx);
builder.arch(Arch.x86);
builder.targetType(ConsoleTarget.TYPE);
builder.mainClass("Main");
builder.addClasspathEntry(p1);
builder.addClasspathEntry(p2);
builder.addClasspathEntry(p3);
builder.addExportedSymbol("YADA*");
builder.addFrameworkPath(new File(p1, "yada"));
builder.addFramework("Yada");
builder.addForceLinkClass("org.yada.**");
builder.addLib(new Lib("yada", true));
builder.addResource(new Resource(new File(p1, "resources")));
builder.addWeakFramework("WeakYada");
builder.home(fakeHome);
Config config = builder.build();
File p1X86Root = new File(p1, "META-INF/robovm/macosx/x86");
File p3X86Cache = config.getCacheDir(config.getClazzes().getClasspathPaths().get(2));
File p3X86Root = new File(p3X86Cache.getParentFile(), p3X86Cache.getName() + ".extracted/META-INF/robovm/macosx/x86");
assertEquals(Arrays.asList("FOO*", "BAAZ*", "YADA*"), config.getExportedSymbols());
assertEquals(Arrays.asList("com.foo.**", "com.baaz.**", "org.yada.**"), config.getForceLinkClasses());
assertEquals(Arrays.asList(
new File(p1X86Root, "foo/bar"),
new File(p3X86Root, "baaz/bar"),
new File(p1, "yada")),
config.getFrameworkPaths());
assertEquals(Arrays.asList("Foo", "Baaz", "Yada"), config.getFrameworks());
assertEquals(Arrays.asList(
new Lib("foo", true),
new Lib(new File(p1X86Root, "libfoo.a").getAbsolutePath(), true),
new Lib("baaz", true),
new Lib(new File(p3X86Root, "libbaaz.a").getAbsolutePath(), true),
new Lib("yada", true)),
config.getLibs());
assertEquals(Arrays.asList(
new Resource(new File(p1X86Root, "resources")),
new Resource(new File(p3X86Root, "resources")),
new Resource(new File(p1, "resources"))),
config.getResources());
assertEquals(Arrays.asList("WeakFoo", "WeakBaaz", "WeakYada"), config.getWeakFrameworks());
// Make sure builder() returns a config which merges in x86_64 configs instead
config = config.builder().arch(Arch.x86_64).build();
File p3X86_64Cache = config.getCacheDir(config.getClazzes().getClasspathPaths().get(2));
File p3X86_64Root = new File(p3X86_64Cache.getParentFile(), p3X86_64Cache.getName() + ".extracted/META-INF/robovm/macosx/x86_64");
assertEquals(Arrays.asList("RAAZ*", "YADA*"), config.getExportedSymbols());
assertEquals(Arrays.asList("com.raaz.**", "org.yada.**"), config.getForceLinkClasses());
assertEquals(Arrays.asList(
new File(p3X86_64Root, "raaz/bar"),
new File(p1, "yada")),
config.getFrameworkPaths());
assertEquals(Arrays.asList("Raaz", "Yada"), config.getFrameworks());
assertEquals(Arrays.asList(
new Lib("raaz", true),
new Lib(new File(p3X86_64Root, "libraaz.a").getAbsolutePath(), true),
new Lib("yada", true)),
config.getLibs());
assertEquals(Arrays.asList(
new Resource(new File(p3X86_64Root, "resources")),
new Resource(new File(p1, "resources"))),
config.getResources());
assertEquals(Arrays.asList("WeakRaaz", "WeakYada"), config.getWeakFrameworks());
}
@Test
public void testCreateBuilderFromConfig() throws Exception {
File tmpDir = createTempDir();
File cacheDir = new File(tmpDir, "cache");
Config.Builder builder = new Config.Builder();
builder.tmpDir(tmpDir);
builder.cacheDir(cacheDir);
builder.os(OS.macosx);
builder.arch(Arch.x86);
builder.targetType(ConsoleTarget.TYPE);
builder.mainClass("Main");
builder.addBootClasspathEntry(new File(tmpDir, "bcp1"));
builder.addBootClasspathEntry(new File(tmpDir, "bcp2"));
builder.addBootClasspathEntry(new File(tmpDir, "bcp3"));
builder.addClasspathEntry(new File(tmpDir, "cp1"));
builder.addClasspathEntry(new File(tmpDir, "cp2"));
builder.addClasspathEntry(new File(tmpDir, "cp3"));
builder.addExportedSymbol("YADA*");
builder.addFrameworkPath(new File(tmpDir, "yada"));
builder.addFramework("Yada");
builder.addForceLinkClass("org.yada.**");
builder.addLib(new Lib("yada", true));
builder.addResource(new Resource(new File(tmpDir, "resources")));
builder.addWeakFramework("WeakYada");
builder.addPluginArgument("foo:bar=yada");
builder.home(fakeHome);
Config config = builder.build();
Builder builder2 = config.builder();
builder2.arch(Arch.arm64);
Config config2 = builder2.build();
assertNotSame(config, config2);
assertEquals(config.getTmpDir(), config2.getTmpDir());
assertEquals(config.getCacheDir().getParentFile().getParentFile(),
config2.getCacheDir().getParentFile().getParentFile());
assertEquals(config.getOs(), config2.getOs());
assertEquals(config.getMainClass(), config2.getMainClass());
assertEquals(config.getBootclasspath(), config2.getBootclasspath());
assertNotSame(config.getBootclasspath(), config2.getBootclasspath());
assertEquals(config.getClasspath(), config2.getClasspath());
assertNotSame(config.getClasspath(), config2.getClasspath());
assertEquals(config.getExportedSymbols(), config2.getExportedSymbols());
assertNotSame(config.getExportedSymbols(), config2.getExportedSymbols());
assertEquals(config.getFrameworkPaths(), config2.getFrameworkPaths());
assertNotSame(config.getFrameworkPaths(), config2.getFrameworkPaths());
assertEquals(config.getFrameworks(), config2.getFrameworks());
assertNotSame(config.getFrameworks(), config2.getFrameworks());
assertEquals(config.getForceLinkClasses(), config2.getForceLinkClasses());
assertNotSame(config.getForceLinkClasses(), config2.getForceLinkClasses());
assertEquals(config.getLibs(), config2.getLibs());
assertNotSame(config.getLibs(), config2.getLibs());
assertEquals(config.getResources(), config2.getResources());
assertNotSame(config.getResources(), config2.getResources());
assertEquals(config.getPluginArguments(), config2.getPluginArguments());
assertNotSame(config.getPluginArguments(), config2.getPluginArguments());
assertEquals(Arch.arm64, config2.getArch());
assertFalse(config.getPlugins().equals(config2.getPlugins()));
assertNotSame(config.getTarget(), config2.getTarget());
assertNotSame(config.getClazzes(), config2.getClazzes());
}
@Test
public void testGetFileName() throws Exception {
assertEquals("201a6b3053cc1422d2c3670b62616221d2290929.class.o", Config.getFileName("Foo", "class.o", 0));
assertEquals("201a6b3053cc1422d2c3670b62616221d2290929.class.o", Config.getFileName("Foo", "class.o", 1));
assertEquals("201a6b3053cc1422d2c3670b62616221d2290929.class.o", Config.getFileName("Foo", "class.o", 10));
assertEquals("Foo.class.o", Config.getFileName("Foo", "class.o", 11));
assertEquals("com/example/201a6b3053cc1422d2c3670b62616221d2290929.class.o",
Config.getFileName("com/example/Foo", "class.o", 0));
assertEquals("com/example/201a6b3053cc1422d2c3670b62616221d2290929.class.o",
Config.getFileName("com/example/Foo", "class.o", 1));
assertEquals("com/example/201a6b3053cc1422d2c3670b62616221d2290929.class.o",
Config.getFileName("com/example/Foo", "class.o", 10));
assertEquals("com/example/Foo.class.o", Config.getFileName("com/example/Foo", "class.o", 11));
assertEquals("com/example/AB9ca44297c0e0d22df654119dce73ee52d3d51c71.class.o",
Config.getFileName("com/example/ABCDEFGIHJABCDEFGIHJABCDEFGIHJABCDEFGIHJABCDEFGIHJ", "class.o", 50));
}
}