diff --git a/src/se/vidstige/jadb/AdbServerLauncher.java b/src/se/vidstige/jadb/AdbServerLauncher.java index 762197f..28bc271 100644 --- a/src/se/vidstige/jadb/AdbServerLauncher.java +++ b/src/se/vidstige/jadb/AdbServerLauncher.java @@ -1,32 +1,30 @@ package se.vidstige.jadb; import java.io.IOException; +import java.util.Map; /** * Launches the ADB server */ public class AdbServerLauncher { - private Runtime runtime; + private final String executable; + private Subprocess subprocess; - public AdbServerLauncher() { - this(Runtime.getRuntime()); + public AdbServerLauncher(Subprocess subprocess, Map environment) { + this.subprocess = subprocess; + this.executable = findAdbExecutable(environment); } - public AdbServerLauncher(Runtime runtime) { - this.runtime = runtime; - } - - private String findAdbExecutable() { - String android_home = System.getenv("ANDROID_HOME"); + private static String findAdbExecutable(Map environment) { + String android_home = environment.get("ANDROID_HOME"); if (android_home == null || android_home.equals("")) { return "adb"; } - return android_home + "/platform-tools/adb"; } public void launch() throws IOException, InterruptedException { - Process p = runtime.exec(new String[]{findAdbExecutable(), "start-server"}); + Process p = subprocess.execute(new String[]{executable, "start-server"}); p.waitFor(); int exitValue = p.exitValue(); if (exitValue != 0) throw new IOException("adb exited with exit code: " + exitValue); diff --git a/src/se/vidstige/jadb/Subprocess.java b/src/se/vidstige/jadb/Subprocess.java new file mode 100644 index 0000000..082d98c --- /dev/null +++ b/src/se/vidstige/jadb/Subprocess.java @@ -0,0 +1,9 @@ +package se.vidstige.jadb; + +import java.io.IOException; + +public class Subprocess { + public Process execute(String[] command) throws IOException { + return Runtime.getRuntime().exec(command); + } +} diff --git a/test/se/vidstige/jadb/test/fakes/FakeProcess.java b/test/se/vidstige/jadb/test/fakes/FakeProcess.java new file mode 100644 index 0000000..7ea2c1d --- /dev/null +++ b/test/se/vidstige/jadb/test/fakes/FakeProcess.java @@ -0,0 +1,41 @@ +package se.vidstige.jadb.test.fakes; + +import java.io.InputStream; +import java.io.OutputStream; + +public class FakeProcess extends Process { + private final int exitValue; + + public FakeProcess(int exitValue) { + this.exitValue = exitValue; + } + + @Override + public OutputStream getOutputStream() { + return null; + } + + @Override + public InputStream getInputStream() { + return null; + } + + @Override + public InputStream getErrorStream() { + return null; + } + + @Override + public int waitFor() throws InterruptedException { + return 0; + } + + @Override + public int exitValue() { + return exitValue; + } + + @Override + public void destroy() { + } +} diff --git a/test/se/vidstige/jadb/test/fakes/FakeSubprocess.java b/test/se/vidstige/jadb/test/fakes/FakeSubprocess.java new file mode 100644 index 0000000..a09556b --- /dev/null +++ b/test/se/vidstige/jadb/test/fakes/FakeSubprocess.java @@ -0,0 +1,72 @@ +package se.vidstige.jadb.test.fakes; + +import se.vidstige.jadb.Subprocess; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FakeSubprocess extends Subprocess { + private List expectations = new ArrayList<>(); + + public Expectation expect(String[] command, int exitValue) { + Expectation builder = new Expectation(command, exitValue); + expectations.add(builder); + return builder; + } + + private String format(String[] command) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < command.length; i++) { + if (i > 0) { + sb.append(" "); + } + sb.append(command[i]); + } + return sb.toString(); + } + + @Override + public Process execute(String[] command) throws IOException { + List toRemove = new ArrayList<>(); + for (Expectation e : expectations) { + if (e.matches(command)) { + toRemove.add(e); + } + } + expectations.removeAll(toRemove); + if (toRemove.size() == 1) { + return new FakeProcess(toRemove.get(0).getExitValue()); + } + throw new AssertionError("Unexpected command: " + format(command)); + } + + public void verifyExpectations() { + if (expectations.size() > 0) { + throw new AssertionError("Subprocess never called: " + format(expectations.get(0).getCommand())); + } + } + + private class Expectation { + private final String[] command; + private final int exitValue; + + public Expectation(String[] command, int exitValue) { + this.command = command; + this.exitValue = exitValue; + } + + public boolean matches(String[] command) { + return Arrays.equals(command, this.command); + } + + public int getExitValue() { + return exitValue; + } + + public String[] getCommand() { + return command; + } + } +} diff --git a/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java b/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java index aaa222e..134353f 100644 --- a/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java +++ b/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java @@ -23,7 +23,7 @@ public class RealDeviceTestCases { @BeforeClass public static void tryToStartAdbServer() { try { - new AdbServerLauncher().launch(); + new AdbServerLauncher(new Subprocess(), System.getenv()).launch(); } catch (IOException e) { System.out.println("Could not start adb-server"); } catch (InterruptedException e) { diff --git a/test/se/vidstige/jadb/test/unit/AdbServerLauncherFixture.java b/test/se/vidstige/jadb/test/unit/AdbServerLauncherFixture.java new file mode 100644 index 0000000..a9b5192 --- /dev/null +++ b/test/se/vidstige/jadb/test/unit/AdbServerLauncherFixture.java @@ -0,0 +1,45 @@ +package se.vidstige.jadb.test.unit; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import se.vidstige.jadb.AdbServerLauncher; +import se.vidstige.jadb.test.fakes.FakeSubprocess; + +import java.io.IOException; +import java.util.*; + +public class AdbServerLauncherFixture { + + private FakeSubprocess subprocess; + private Map environment = new HashMap<>(); + + @Before + public void setUp() { + subprocess = new FakeSubprocess(); + } + @After + public void tearDown() { + subprocess.verifyExpectations(); + } + + @Test + public void testStartServer() throws Exception { + subprocess.expect(new String[]{"/abc/platform-tools/adb", "start-server"}, 0); + Map environment = new HashMap<>(); + environment.put("ANDROID_HOME", "/abc"); + new AdbServerLauncher(subprocess, environment).launch(); + } + + @Test + public void testStartServerWithoutANDROID_HOME() throws Exception { + subprocess.expect(new String[]{"adb", "start-server"}, 0); + new AdbServerLauncher(subprocess, environment).launch(); + } + + @Test(expected=IOException.class) + public void testStartServerFails() throws Exception { + subprocess.expect(new String[]{"adb", "start-server"}, -1); + new AdbServerLauncher(subprocess, environment).launch(); + } +}