diff --git a/api/net/sf/briar/api/setup/SetupParameters.java b/api/net/sf/briar/api/setup/SetupParameters.java index 9408e9b82f2abc3c4f997ffb4ba7700c441ffea0..be90063496b962ddada6c2181fff438009d20417 100644 --- a/api/net/sf/briar/api/setup/SetupParameters.java +++ b/api/net/sf/briar/api/setup/SetupParameters.java @@ -7,4 +7,6 @@ public interface SetupParameters { File getChosenLocation(); String[] getBundledFontFilenames(); + + long getExeHeaderSize(); } diff --git a/components/net/sf/briar/setup/SetupModule.java b/components/net/sf/briar/setup/SetupModule.java deleted file mode 100644 index 71dd5b0ea93d18feebc5fa2c017fbac18245cceb..0000000000000000000000000000000000000000 --- a/components/net/sf/briar/setup/SetupModule.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.sf.briar.setup; - -import net.sf.briar.api.setup.SetupWorkerFactory; - -import com.google.inject.AbstractModule; - -public class SetupModule extends AbstractModule { - - @Override - protected void configure() { - bind(SetupWorkerFactory.class).to(SetupWorkerFactoryImpl.class); - } -} diff --git a/components/net/sf/briar/setup/SetupWorker.java b/components/net/sf/briar/setup/SetupWorker.java index ccfa490acec9b987b4129292729ab9b6f71b6136..389a246b96ffb1d29074628959c7639c6c24f439 100644 --- a/components/net/sf/briar/setup/SetupWorker.java +++ b/components/net/sf/briar/setup/SetupWorker.java @@ -5,7 +5,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; -import java.security.CodeSource; import net.sf.briar.api.i18n.I18n; import net.sf.briar.api.setup.SetupCallback; @@ -18,18 +17,19 @@ class SetupWorker implements Runnable { private static final String MAIN_CLASS = "net.sf.briar.ui.invitation.InvitationMain"; - private static final int EXE_HEADER_SIZE = 62976; private final SetupCallback callback; private final SetupParameters parameters; private final I18n i18n; + private final File jar; private final ZipUtils.Callback unzipCallback; SetupWorker(final SetupCallback callback, SetupParameters parameters, - I18n i18n) { + I18n i18n, File jar) { this.parameters = parameters; this.callback = callback; this.i18n = i18n; + this.jar = jar; unzipCallback = new ZipUtils.Callback() { public void processingFile(File f) { callback.extractingFile(f); @@ -38,6 +38,10 @@ class SetupWorker implements Runnable { } public void run() { + if(!jar.isFile()) { + callback.error("Not running from jar"); + return; + } File dir = parameters.getChosenLocation(); assert dir != null; if(!dir.exists()) { @@ -66,8 +70,6 @@ class SetupWorker implements Runnable { return; } try { - if(callback.isCancelled()) return; - File jar = getJar(); if(callback.isCancelled()) return; copyInstaller(jar, data); if(callback.isCancelled()) return; @@ -86,14 +88,6 @@ class SetupWorker implements Runnable { callback.installed(dir); } - private File getJar() throws IOException { - CodeSource c = FileUtils.class.getProtectionDomain().getCodeSource(); - File jar = new File(c.getLocation().getPath()); - assert jar.exists(); - if(!jar.isFile()) throw new IOException("Not running from a jar"); - return jar; - } - private void copyInstaller(File jar, File dir) throws IOException { File dest = new File(dir, "setup.dat"); callback.copyingFile(dest); @@ -103,7 +97,7 @@ class SetupWorker implements Runnable { private void extractFiles(File jar, File dir, String regex) throws IOException { FileInputStream in = new FileInputStream(jar); - in.skip(EXE_HEADER_SIZE); + in.skip(parameters.getExeHeaderSize()); ZipUtils.unzipStream(in, dir, regex, unzipCallback); } diff --git a/components/net/sf/briar/setup/SetupWorkerFactoryImpl.java b/components/net/sf/briar/setup/SetupWorkerFactoryImpl.java index 51425399cedd2d6f167018601ca84bc8a90cb4c1..0df98b59ad0b39389db646b940f1ce11ca8b6b6d 100644 --- a/components/net/sf/briar/setup/SetupWorkerFactoryImpl.java +++ b/components/net/sf/briar/setup/SetupWorkerFactoryImpl.java @@ -1,23 +1,27 @@ package net.sf.briar.setup; +import java.io.File; +import java.security.CodeSource; + import net.sf.briar.api.i18n.I18n; import net.sf.briar.api.setup.SetupCallback; import net.sf.briar.api.setup.SetupParameters; import net.sf.briar.api.setup.SetupWorkerFactory; - -import com.google.inject.Inject; +import net.sf.briar.util.FileUtils; public class SetupWorkerFactoryImpl implements SetupWorkerFactory { private final I18n i18n; - @Inject public SetupWorkerFactoryImpl(I18n i18n) { this.i18n = i18n; } public Runnable createWorker(SetupCallback callback, SetupParameters parameters) { - return new SetupWorker(callback, parameters, i18n); + CodeSource c = FileUtils.class.getProtectionDomain().getCodeSource(); + File jar = new File(c.getLocation().getPath()); + assert jar.exists(); + return new SetupWorker(callback, parameters, i18n, jar); } } diff --git a/test/build.xml b/test/build.xml index dfc757721352458e13b4f5ebb0b04406e0d31610..9c90d42b1299ec8fe1954b8264ed9e8068abcbc8 100644 --- a/test/build.xml +++ b/test/build.xml @@ -1,7 +1,7 @@ <project name='test' default='test'> <import file='../build-common.xml'/> <target name='test' depends='depend'> - <junit haltonfailure='true' printsummary='on' showoutput='true'> + <junit printsummary='on'> <classpath> <fileset refid='bundled-jars'/> <fileset refid='test-jars'/> @@ -10,7 +10,10 @@ <path refid='test-classes'/> <path refid='util-classes'/> </classpath> + <test name='net.sf.briar.setup.SetupWorkerTest'/> <test name='net.sf.briar.util.FileUtilsTest'/> + <test name='net.sf.briar.util.StringUtilsTest'/> + <test name='net.sf.briar.util.ZipUtilsTest'/> </junit> </target> </project> diff --git a/test/net/sf/briar/util/TestUtils.java b/test/net/sf/briar/TestUtils.java similarity index 66% rename from test/net/sf/briar/util/TestUtils.java rename to test/net/sf/briar/TestUtils.java index 5bfe71fbb8a8a1d17ca8ca10a414ad15732a9ba0..8e3e8daf30e270f1e9b1162bea1eef317f655d33 100644 --- a/test/net/sf/briar/util/TestUtils.java +++ b/test/net/sf/briar/TestUtils.java @@ -1,18 +1,18 @@ -package net.sf.briar.util; +package net.sf.briar; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; -class TestUtils { +public class TestUtils { - static void delete(File f) throws IOException { + public static void delete(File f) throws IOException { if(f.isDirectory()) for(File child : f.listFiles()) delete(child); f.delete(); } - static void createFile(File f, String s) throws IOException { + public static void createFile(File f, String s) throws IOException { f.getParentFile().mkdirs(); PrintStream out = new PrintStream(new FileOutputStream(f)); out.print(s); diff --git a/test/net/sf/briar/setup/SetupWorkerTest.java b/test/net/sf/briar/setup/SetupWorkerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ca88539be1416a03b94a0706af74bb34498c8a3c --- /dev/null +++ b/test/net/sf/briar/setup/SetupWorkerTest.java @@ -0,0 +1,168 @@ +package net.sf.briar.setup; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipOutputStream; + +import junit.framework.TestCase; +import net.sf.briar.TestUtils; +import net.sf.briar.api.i18n.I18n; +import net.sf.briar.api.setup.SetupCallback; +import net.sf.briar.api.setup.SetupParameters; +import net.sf.briar.util.ZipUtils; + +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class SetupWorkerTest extends TestCase { + + private static final int HEADER_SIZE = 1234; + + private final File testDir = new File("test.tmp"); + private final File jar = new File(testDir, "test.jar"); + + @Before + public void setUp() throws IOException { + testDir.mkdirs(); + jar.createNewFile(); + } + + @Test + public void testHaltsIfNotRunningFromJar() { + Mockery context = new Mockery(); + final SetupCallback callback = context.mock(SetupCallback.class); + SetupParameters params = context.mock(SetupParameters.class); + I18n i18n = context.mock(I18n.class); + context.checking(new Expectations() {{ + oneOf(callback).error("Not running from jar"); + }}); + + new SetupWorker(callback, params, i18n, testDir).run(); + + context.assertIsSatisfied(); + File[] children = testDir.listFiles(); + assertNotNull(children); + assertEquals(1, children.length); + assertEquals(jar, children[0]); + } + + @Test + public void testHaltsIfDestinationDoesNotExist() { + final File nonExistent = new File(testDir, "does.not.exist"); + Mockery context = new Mockery(); + final SetupCallback callback = context.mock(SetupCallback.class); + final SetupParameters params = context.mock(SetupParameters.class); + I18n i18n = context.mock(I18n.class); + context.checking(new Expectations() {{ + oneOf(params).getChosenLocation(); + will(returnValue(nonExistent)); + oneOf(callback).notFound(nonExistent); + }}); + + new SetupWorker(callback, params, i18n, jar).run(); + + context.assertIsSatisfied(); + File[] children = testDir.listFiles(); + assertNotNull(children); + assertEquals(1, children.length); + assertEquals(jar, children[0]); + } + + @Test + public void testHaltsIfDestinationIsNotADirectory() { + Mockery context = new Mockery(); + final SetupCallback callback = context.mock(SetupCallback.class); + final SetupParameters params = context.mock(SetupParameters.class); + I18n i18n = context.mock(I18n.class); + context.checking(new Expectations() {{ + oneOf(params).getChosenLocation(); + will(returnValue(jar)); + oneOf(callback).notDirectory(jar); + }}); + + new SetupWorker(callback, params, i18n, jar).run(); + + context.assertIsSatisfied(); + File[] children = testDir.listFiles(); + assertNotNull(children); + assertEquals(1, children.length); + assertEquals(jar, children[0]); + } + + @Test + public void testCreatesExpectedFiles() throws IOException { + final File setupDat = new File(testDir, "Briar/Data/setup.dat"); + final File jreFoo = new File(testDir, "Briar/Data/jre/foo"); + final File fooJar = new File(testDir, "Briar/Data/foo.jar"); + final File fooTtf = new File(testDir, "Briar/Data/foo.ttf"); + final File fooXyz = new File(testDir, "Briar/Data/foo.xyz"); + createJar(); + + Mockery context = new Mockery(); + final SetupCallback callback = context.mock(SetupCallback.class); + final SetupParameters params = context.mock(SetupParameters.class); + final I18n i18n = context.mock(I18n.class); + context.checking(new Expectations() {{ + oneOf(params).getChosenLocation(); + will(returnValue(testDir)); + allowing(callback).isCancelled(); + will(returnValue(false)); + oneOf(callback).copyingFile(setupDat); + oneOf(params).getExeHeaderSize(); + will(returnValue((long) HEADER_SIZE)); + oneOf(callback).extractingFile(jreFoo); + oneOf(callback).extractingFile(fooJar); + oneOf(callback).extractingFile(fooTtf); + oneOf(i18n).saveLocale(new File(testDir, "Briar/Data")); + oneOf(callback).installed(new File(testDir, "Briar")); + }}); + + new SetupWorker(callback, params, i18n, jar).run(); + + context.assertIsSatisfied(); + assertTrue(setupDat.exists()); + assertTrue(setupDat.isFile()); + assertEquals(jar.length(), setupDat.length()); + assertTrue(jreFoo.exists()); + assertTrue(jreFoo.isFile()); + assertEquals("one one one".length(), jreFoo.length()); + assertTrue(fooJar.exists()); + assertTrue(fooJar.isFile()); + assertEquals("two two two".length(), fooJar.length()); + assertTrue(fooTtf.exists()); + assertTrue(fooTtf.isFile()); + assertEquals("three three three".length(), fooTtf.length()); + assertFalse(fooXyz.exists()); + } + + private void createJar() throws IOException { + FileOutputStream out = new FileOutputStream(jar); + byte[] header = new byte[HEADER_SIZE]; + out.write(header); + ZipOutputStream zip = new ZipOutputStream(out); + File temp = new File(testDir, "temp"); + TestUtils.createFile(temp, "one one one"); + ZipUtils.copyToZip("jre/foo", temp, zip); + temp.delete(); + TestUtils.createFile(temp, "two two two"); + ZipUtils.copyToZip("foo.jar", temp, zip); + temp.delete(); + TestUtils.createFile(temp, "three three three"); + ZipUtils.copyToZip("foo.ttf", temp, zip); + temp.delete(); + TestUtils.createFile(temp, "four four four"); + ZipUtils.copyToZip("foo.xyz", temp, zip); + temp.delete(); + zip.flush(); + zip.close(); + } + + @After + public void tearDown() throws IOException { + TestUtils.delete(testDir); + } +} diff --git a/test/net/sf/briar/util/FileUtilsTest.java b/test/net/sf/briar/util/FileUtilsTest.java index 1b76d85705a1ed6b1bad16b045cae92ae869db4b..94fe9476e33fb6e0e1aae977da557a63daab6d76 100644 --- a/test/net/sf/briar/util/FileUtilsTest.java +++ b/test/net/sf/briar/util/FileUtilsTest.java @@ -7,6 +7,7 @@ import java.io.InputStream; import java.util.Scanner; import junit.framework.TestCase; +import net.sf.briar.TestUtils; import net.sf.briar.util.FileUtils.Callback; import org.jmock.Expectations; diff --git a/test/net/sf/briar/util/ZipUtilsTest.java b/test/net/sf/briar/util/ZipUtilsTest.java index f6c1d91e04f23e73a4b0b23f53b35695ebe21383..4e95a437fac193b6ae16aff4e4034196c1befb8c 100644 --- a/test/net/sf/briar/util/ZipUtilsTest.java +++ b/test/net/sf/briar/util/ZipUtilsTest.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.Map; import java.util.Scanner; import java.util.TreeMap; @@ -12,6 +13,7 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import junit.framework.TestCase; +import net.sf.briar.TestUtils; import net.sf.briar.util.ZipUtils.Callback; import org.jmock.Expectations; @@ -24,6 +26,10 @@ public class ZipUtilsTest extends TestCase { private final File testDir = new File("test.tmp"); + private final File f1 = new File(testDir, "abc/def/1"); + private final File f2 = new File(testDir, "abc/def/2"); + private final File f3 = new File(testDir, "abc/3"); + @Before public void setUp() { testDir.mkdirs(); @@ -72,15 +78,12 @@ public class ZipUtilsTest extends TestCase { @Test public void testCopyToZipRecursively() throws IOException { - final File src1 = new File(testDir, "abc/def/1"); - final File src2 = new File(testDir, "abc/def/2"); - final File src3 = new File(testDir, "abc/3"); Mockery context = new Mockery(); final Callback callback = context.mock(Callback.class); context.checking(new Expectations() {{ - oneOf(callback).processingFile(src1); - oneOf(callback).processingFile(src2); - oneOf(callback).processingFile(src3); + oneOf(callback).processingFile(f1); + oneOf(callback).processingFile(f2); + oneOf(callback).processingFile(f3); }}); copyRecursively(callback); @@ -94,10 +97,9 @@ public class ZipUtilsTest extends TestCase { } private void copyRecursively(Callback callback) throws IOException { - TestUtils.createFile(new File(testDir, "abc/def/1"), "one one one"); - TestUtils.createFile(new File(testDir, "abc/def/2"), "two two two"); - TestUtils.createFile(new File(testDir, "abc/3"), "three three three"); - + TestUtils.createFile(f1, "one one one"); + TestUtils.createFile(f2, "two two two"); + TestUtils.createFile(f3, "three three three"); File src = new File(testDir, "abc"); File dest = new File(testDir, "dest"); ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(dest)); @@ -113,6 +115,85 @@ public class ZipUtilsTest extends TestCase { checkZipEntries(dest, expected); } + @Test + public void testUnzipStream() throws IOException { + Mockery context = new Mockery(); + final Callback callback = context.mock(Callback.class); + context.checking(new Expectations() {{ + oneOf(callback).processingFile(f1); + oneOf(callback).processingFile(f2); + oneOf(callback).processingFile(f3); + }}); + + unzipStream(null, callback); + + context.assertIsSatisfied(); + + assertTrue(f1.exists()); + assertTrue(f1.isFile()); + assertEquals("one one one".length(), f1.length()); + assertTrue(f2.exists()); + assertTrue(f2.isFile()); + assertEquals("two two two".length(), f2.length()); + assertTrue(f3.exists()); + assertTrue(f3.isFile()); + assertEquals("three three three".length(), f3.length()); + } + + @Test + public void testUnzipStreamWithRegex() throws IOException { + Mockery context = new Mockery(); + final Callback callback = context.mock(Callback.class); + context.checking(new Expectations() {{ + oneOf(callback).processingFile(f1); + oneOf(callback).processingFile(f2); + }}); + + unzipStream("^abc/def/.*", callback); + + context.assertIsSatisfied(); + + assertTrue(f1.exists()); + assertTrue(f1.isFile()); + assertEquals("one one one".length(), f1.length()); + assertTrue(f2.exists()); + assertTrue(f2.isFile()); + assertEquals("two two two".length(), f2.length()); + assertFalse(f3.exists()); + } + + @Test + public void testUnzipStreamNoCallback() throws IOException { + unzipStream(null, null); + + assertTrue(f1.exists()); + assertTrue(f1.isFile()); + assertEquals("one one one".length(), f1.length()); + assertTrue(f2.exists()); + assertTrue(f2.isFile()); + assertEquals("two two two".length(), f2.length()); + assertTrue(f3.exists()); + assertTrue(f3.isFile()); + assertEquals("three three three".length(), f3.length()); + } + + private void unzipStream(String regex, Callback callback) + throws IOException { + TestUtils.createFile(f1, "one one one"); + TestUtils.createFile(f2, "two two two"); + TestUtils.createFile(f3, "three three three"); + File src = new File(testDir, "abc"); + File dest = new File(testDir, "dest"); + ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(dest)); + ZipUtils.copyToZipRecursively(src.getName(), src, zip, null); + zip.flush(); + zip.close(); + TestUtils.delete(src); + + InputStream in = new FileInputStream(dest); + ZipUtils.unzipStream(in, testDir, regex, callback); + } + @After public void tearDown() throws IOException { TestUtils.delete(testDir); diff --git a/ui/net/sf/briar/ui/setup/SetupParametersImpl.java b/ui/net/sf/briar/ui/setup/SetupParametersImpl.java index 1aca3ec08bee2b1a70cc401a53d627227ee7be13..0fb1b72a483afd3759da7f59d371cd914beca892 100644 --- a/ui/net/sf/briar/ui/setup/SetupParametersImpl.java +++ b/ui/net/sf/briar/ui/setup/SetupParametersImpl.java @@ -7,6 +7,8 @@ import net.sf.briar.api.setup.SetupParameters; class SetupParametersImpl implements SetupParameters { + private static final int EXE_HEADER_SIZE = 62976; + private final LocationPanel locationPanel; private final FontManager fontManager; @@ -22,4 +24,8 @@ class SetupParametersImpl implements SetupParameters { public String[] getBundledFontFilenames() { return fontManager.getBundledFontFilenames(); } + + public long getExeHeaderSize() { + return EXE_HEADER_SIZE; + } } diff --git a/util/net/sf/briar/util/ZipUtils.java b/util/net/sf/briar/util/ZipUtils.java index 202a9b086e930853f29910212a4b893b6dd898ca..71777b5f47ee68bfd278c65e1b59d72844eb275d 100644 --- a/util/net/sf/briar/util/ZipUtils.java +++ b/util/net/sf/briar/util/ZipUtils.java @@ -54,18 +54,18 @@ public class ZipUtils { /** * Unzips the given stream to the given directory, skipping any zip entries - * that don't match the given regex. If the callback is not null it's - * called once for each file extracted. + * that don't match the given regex (a null regex matches all entries). If + * the callback is not null it's called once for each file extracted. */ public static void unzipStream(InputStream in, File dir, String regex, Callback callback) throws IOException { - String path = dir.getCanonicalPath(); + String path = dir.getPath(); ZipInputStream zip = new ZipInputStream(in); byte[] buf = new byte[1024]; ZipEntry entry; while((entry = zip.getNextEntry()) != null) { String name = entry.getName(); - if(name.matches(regex)) { + if(regex == null || name.matches(regex)) { File file = new File(path + "/" + name); if(callback != null) callback.processingFile(file); if(entry.isDirectory()) {