diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2013-12-17 12:09:52 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2013-12-17 12:09:52 +0100 |
commit | 2f82a417928c69f1b3d34c49532eed07c90689e9 (patch) | |
tree | b7fcc608f7d736e42ea20dd7a63691de188b6aaf /sonar-plugin-api | |
parent | 15840de6781ce67c5acc948f4b45a67d842f742d (diff) | |
download | sonarqube-2f82a417928c69f1b3d34c49532eed07c90689e9.tar.gz sonarqube-2f82a417928c69f1b3d34c49532eed07c90689e9.zip |
New class System2 to increase testability of classes that call low-level system methods
Diffstat (limited to 'sonar-plugin-api')
5 files changed, 220 insertions, 29 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/System2.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/System2.java new file mode 100644 index 00000000000..a87dedbdb33 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/System2.java @@ -0,0 +1,102 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.api.utils; + +import org.apache.commons.lang.SystemUtils; + +import javax.annotation.CheckForNull; +import java.util.Map; +import java.util.Properties; + +/** + * Proxy over {@link java.lang.System}. It aims to improve testability of classes + * that interact with low-level system methods, for example : + * + * <pre> + * public class MyClass { + * private final System2 system; + * + * public MyClass(System2 s) { + * this.system = s; + * } + * + * public long xxx() { + * return system.now(); + * } + * } + * + * @Test + * public void should_return_xxx() { + * System2 system = mock(System2.class); + * long now = parse("2013-12-25"); + * doReturn(now).when(system).now(); + * assertThat(new MyClass(system).xxx()).isEqualTo(now); + * } + * </pre> + * + * @since 4.2 + */ +public class System2 { + + public static final System2 INSTANCE = new System2(); + + /** + * Shortcut for {@link System#currentTimeMillis()} + */ + public long now() { + return System.currentTimeMillis(); + } + + /** + * Shortcut for {@link System#getProperties()} + */ + public Properties properties() { + return System.getProperties(); + } + + /** + * Shortcut for {@link System#getProperty(String)} + */ + @CheckForNull + public String property(String key) { + return System.getProperty(key); + } + + /** + * Shortcut for {@link System#getenv()} + */ + public Map<String, String> envVariables() { + return System.getenv(); + } + + /** + * Shortcut for {@link System#getenv(String)} + */ + public String envVariable(String key) { + return System.getenv(key); + } + + /** + * True if this is MS Windows. + */ + public boolean isOsWindows() { + return SystemUtils.IS_OS_WINDOWS; + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/Command.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/Command.java index c53563ce216..7a39f6a2a7b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/Command.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/Command.java @@ -26,7 +26,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.SystemUtils; +import org.sonar.api.utils.System2; import java.io.File; import java.util.Collections; @@ -39,13 +39,25 @@ import java.util.Map; public class Command { private final String executable; private final List<String> arguments = Lists.newArrayList(); - private final Map<String, String> env = Maps.newHashMap(System.getenv()); + private final Map<String, String> env; private File directory; private boolean newShell = false; + private final System2 system; - private Command(String executable) { + /** + * Create a command line without any arguments + * + * @param executable + */ + public static Command create(String executable) { + return new Command(executable, System2.INSTANCE); + } + + Command(String executable, System2 system) { Preconditions.checkArgument(!StringUtils.isBlank(executable), "Command executable can not be blank"); this.executable = executable; + this.env = Maps.newHashMap(system.envVariables()); + this.system = system; } public String getExecutable() { @@ -130,7 +142,7 @@ public class Command { List<String> toStrings() { ImmutableList.Builder<String> command = ImmutableList.builder(); if (newShell) { - if (SystemUtils.IS_OS_WINDOWS) { + if (system.isOsWindows()) { command.add("cmd", "/C", "call"); } else { command.add("sh"); @@ -149,13 +161,4 @@ public class Command { public String toString() { return toCommandLine(); } - - /** - * Create a command line without any arguments - * - * @param executable - */ - public static Command create(String executable) { - return new Command(executable); - } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/System2Test.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/System2Test.java new file mode 100644 index 00000000000..b81a065bacc --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/System2Test.java @@ -0,0 +1,72 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.api.utils; + +import org.apache.commons.lang.SystemUtils; +import org.junit.Test; + +import java.util.Map; +import java.util.Properties; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + +public class System2Test { + @Test + public void testNow() throws Exception { + long start = System.currentTimeMillis(); + long now = System2.INSTANCE.now(); + assertThat(now-start).isGreaterThanOrEqualTo(0).isLessThan(3); + } + + @Test + public void testProperties() throws Exception { + Properties expected = System.getProperties(); + assertThat(System2.INSTANCE.properties()).isNotNull().isEqualTo(expected); + } + + @Test + public void testProperty() throws Exception { + String expected = System.getProperty("java.version"); + assertThat(System2.INSTANCE.property("java.version")).isNotNull().isEqualTo(expected); + } + + @Test + public void testEnvVariables() throws Exception { + Map<String,String> expected = System.getenv(); + assertThat(System2.INSTANCE.envVariables()).isNotNull().isEqualTo(expected); + } + + @Test + public void testEnvVariable() throws Exception { + // assume that there's at least one env variable + if (System.getenv().isEmpty()) { + fail("Test can't succeed because there are no env variables. How is it possible ?"); + } + String key = System.getenv().keySet().iterator().next(); + String expected = System.getenv(key); + assertThat(System2.INSTANCE.envVariable(key)).isNotNull().isEqualTo(expected); + } + + @Test + public void testIsOsWindows() throws Exception { + assertThat(System2.INSTANCE.isOsWindows()).isEqualTo(SystemUtils.IS_OS_WINDOWS); + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandExecutorTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandExecutorTest.java index 2c79502b9f2..e898a966819 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandExecutorTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandExecutorTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; +import org.sonar.api.utils.System2; import java.io.File; import java.io.IOException; @@ -145,7 +146,7 @@ public class CommandExecutorTest { private static String getScript(String name) throws IOException { String filename; - if (SystemUtils.IS_OS_WINDOWS) { + if (System2.INSTANCE.isOsWindows()) { filename = name + ".bat"; } else { filename = name + ".sh"; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandTest.java index db99f370078..296b19859a1 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandTest.java @@ -19,15 +19,18 @@ */ package org.sonar.api.utils.command; -import org.apache.commons.lang.SystemUtils; +import com.google.common.collect.ImmutableMap; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; import java.io.File; import java.util.Arrays; import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class CommandTest { @@ -82,24 +85,34 @@ public class CommandTest { @Test public void override_env_variables() { - Command command = Command.create("java"); - command.setEnvironmentVariable("JAVA_HOME", "/path/to/java"); - assertThat(command.getEnvironmentVariables().get("JAVA_HOME")).isEqualTo("/path/to/java"); + System2 system = mock(System2.class); + when(system.envVariables()).thenReturn(ImmutableMap.of("JAVA_HOME", "/default/path/to/java")); + + Command command = new Command("java", system); + command.setEnvironmentVariable("JAVA_HOME", "/new/path/to/java"); + assertThat(command.getEnvironmentVariables().get("JAVA_HOME")).isEqualTo("/new/path/to/java"); } @Test - public void should_use_new_shell() { - if (SystemUtils.IS_OS_WINDOWS) { - Command command = Command.create("foo.bat"); - command.setNewShell(true); - assertThat(command.toCommandLine()).isEqualTo("cmd /C call foo.bat"); + public void should_use_cmd_for_new_shell_on_windows() { + System2 system = mock(System2.class); + when(system.isOsWindows()).thenReturn(true); + Command command = new Command("foo.bat", system); + command.setNewShell(true); + assertThat(command.toCommandLine()).isEqualTo("cmd /C call foo.bat"); assertThat(command.isNewShell()).isTrue(); - } else { - Command command = Command.create("foo.sh"); - command.setNewShell(true); - assertThat(command.toCommandLine()).isEqualTo("sh foo.sh"); - assertThat(command.isNewShell()).isTrue(); - } + + } + + @Test + public void should_use_sh_for_new_shell_on_unix() { + System2 system = mock(System2.class); + when(system.isOsWindows()).thenReturn(false); + Command command = new Command("foo.sh", system); + + command.setNewShell(true); + assertThat(command.toCommandLine()).isEqualTo("sh foo.sh"); + assertThat(command.isNewShell()).isTrue(); } @Test |