blob: 131fcf6e41cc9ce2ee0256cceb8a5a575f628403 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* 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.intellij.execution;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.util.ExecUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Function;
import org.jetbrains.annotations.Nullable;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;
public class GeneralCommandLineTest {
@Test
public void printCommandLine() {
GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.setExePath("e x e path");
commandLine.addParameter("with space");
commandLine.addParameter("\"quoted\"");
commandLine.addParameter("\"quoted with spaces\"");
commandLine.addParameters("param 1", "param2");
commandLine.addParameter("trailing slash\\");
assertEquals("\"e x e path\"" +
" \"with space\"" +
" \\\"quoted\\\"" +
" \"\\\"quoted with spaces\\\"\"" +
" \"param 1\"" +
" param2" +
" \"trailing slash\\\"",
commandLine.getCommandLineString());
}
@Test
public void unicodePath() throws Exception {
String mark = String.valueOf(new Random().nextInt());
File script;
if (SystemInfo.isWindows) {
script = ExecUtil.createTempExecutableScript(
"path with spaces 'and quotes' и юникодом ", ".cmd",
"@echo " + mark + "\n"
);
}
else {
script = ExecUtil.createTempExecutableScript(
"path with spaces 'and quotes' и юникодом ", ".sh",
"#!/bin/sh\n" + "echo " + mark + "\n"
);
}
try {
GeneralCommandLine commandLine = new GeneralCommandLine(script.getPath());
String output = execAndGetOutput(commandLine, null);
assertEquals(mark + "\n", StringUtil.convertLineSeparators(output));
}
finally {
FileUtil.delete(script);
}
}
@Test
public void unicodeClassPath() throws Exception {
assumeTrue(SystemInfo.isUnix);
File dir = FileUtil.createTempDirectory("path with spaces 'and quotes' и юникодом ", ".tmp");
try {
GeneralCommandLine commandLine = makeJavaCommand(ParamPassingTest.class, dir);
String output = execAndGetOutput(commandLine, null);
assertEquals("=====\n=====\n", StringUtil.convertLineSeparators(output));
}
finally {
FileUtil.delete(dir);
}
}
@Test
public void argumentsPassing() throws Exception {
String[] parameters = {
"with space", "\"quoted\"", "\"quoted with spaces\"", "", " ", "param 1", "\"", "param2", "trailing slash\\"
};
GeneralCommandLine commandLine = makeJavaCommand(ParamPassingTest.class, null);
commandLine.addParameters(parameters);
String output = execAndGetOutput(commandLine, null);
assertEquals("=====\n" + StringUtil.join(parameters, new Function<String, String>() {
@Override
public String fun(String s) {
return ParamPassingTest.format(s);
}
}, "\n") + "\n=====\n", StringUtil.convertLineSeparators(output));
}
@Test
public void unicodeArguments() throws Exception {
assumeTrue("UTF-8".equals(System.getProperty("file.encoding")));
File script;
GeneralCommandLine commandLine;
String encoding = null;
if (SystemInfo.isWindows) {
script = ExecUtil.createTempExecutableScript(
"args.", ".js",
"WSH.Echo(\"=====\");\n" +
"for (i = 0; i < WSH.Arguments.length; i++) {\n" +
" WSH.Echo(WSH.Arguments(i));\n" +
"}\n" +
"WSH.Echo(\"=====\");\n"
);
commandLine = new GeneralCommandLine("cscript", "//Nologo", "//U", script.getPath());
encoding = "UTF-16LE";
}
else {
script = ExecUtil.createTempExecutableScript(
"args.", ".sh",
"#!/bin/sh\n\n" +
"echo \"=====\"\n" +
"for f in \"$@\" ; do echo \"$f\"; done\n" +
"echo \"=====\"\n"
);
commandLine = new GeneralCommandLine(script.getPath());
}
try {
commandLine.addParameters("немного", "юникодных", "параметров");
String output = execAndGetOutput(commandLine, encoding);
assertEquals("=====\nнемного\nюникодных\nпараметров\n=====\n", StringUtil.convertLineSeparators(output));
}
finally {
FileUtil.delete(script);
}
}
@Test
public void winShellCommand() throws Exception {
assumeTrue(SystemInfo.isWindows);
String string = "http://localhost/wtf?a=b&c=d";
String echo = ExecUtil.execAndReadLine(ExecUtil.getWindowsShellName(), "/c", "echo", string);
assertEquals('"' + string + '"', echo);
}
@Test
public void winShellScriptQuoting() throws Exception {
assumeTrue(SystemInfo.isWindows);
String scriptPrefix = "my_script";
for (String cmdScriptExt : new String[] {".cmd", ".bat"}) {
File script = ExecUtil.createTempExecutableScript(
scriptPrefix, cmdScriptExt,
"@echo %1\n"
);
String param = "a&b";
GeneralCommandLine commandLine = new GeneralCommandLine(script.getAbsolutePath(), param);
String text = commandLine.getPreparedCommandLine(Platform.WINDOWS);
assertEquals(commandLine.getExePath() + "\n" + StringUtil.wrapWithDoubleQuote(param), text);
try {
String output = execAndGetOutput(commandLine, null);
assertEquals(StringUtil.wrapWithDoubleQuote(param), output.trim());
}
finally {
FileUtil.delete(script);
}
}
}
@Test
public void winShellQuotingWithExtraSwitch() throws Exception {
assumeTrue(SystemInfo.isWindows);
String param = "a&b";
GeneralCommandLine commandLine = new GeneralCommandLine("cmd", "/D", "/C", "echo", param);
String output = execAndGetOutput(commandLine, null);
assertEquals(StringUtil.wrapWithDoubleQuote(param), output.trim());
}
@Test
public void hackyEnvMap () throws Exception {
GeneralCommandLine commandLine = new GeneralCommandLine();
//noinspection ConstantConditions
commandLine.getEnvironment().putAll(null);
}
@Test
public void environmentPassing() throws Exception {
Map<String, String> testEnv = new HashMap<String, String>();
testEnv.put("VALUE_1", "some value");
testEnv.put("VALUE_2", "another\n\"value\"");
GeneralCommandLine commandLine = makeJavaCommand(EnvPassingTest.class, null);
checkEnvPassing(commandLine, testEnv, true);
checkEnvPassing(commandLine, testEnv, false);
}
@Test
public void unicodeEnvironment() throws Exception {
assumeTrue("UTF-8".equals(System.getProperty("file.encoding")));
Map<String, String> testEnv = new HashMap<String, String>();
testEnv.put("VALUE_1", "немного");
testEnv.put("VALUE_2", "юникода");
GeneralCommandLine commandLine = makeJavaCommand(EnvPassingTest.class, null);
checkEnvPassing(commandLine, testEnv, true);
checkEnvPassing(commandLine, testEnv, false);
}
private static String execAndGetOutput(GeneralCommandLine commandLine, @Nullable String encoding) throws Exception {
Process process = commandLine.createProcess();
byte[] bytes = FileUtil.loadBytes(process.getInputStream());
String output = encoding != null ? new String(bytes, encoding) : new String(bytes);
int result = process.waitFor();
assertEquals("Command:\n" + commandLine.getCommandLineString() + "\nOutput:\n" + output, 0, result);
return output;
}
private GeneralCommandLine makeJavaCommand(Class<?> testClass, @Nullable File copyTo) throws IOException {
String className = testClass.getName();
URL url = getClass().getClassLoader().getResource(className.replace(".", "/") + ".class");
assertNotNull(url);
GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.setExePath(System.getProperty("java.home") + (SystemInfo.isWindows ? "\\bin\\java.exe" : "/bin/java"));
String encoding = System.getProperty("file.encoding");
if (encoding != null) {
commandLine.addParameter("-D" + "file.encoding=" + encoding);
}
commandLine.addParameter("-cp");
String[] packages = className.split("\\.");
File classFile = new File(url.getFile());
if (copyTo == null) {
File dir = classFile;
for (String ignored : packages) dir = dir.getParentFile();
commandLine.addParameter(dir.getPath());
}
else {
File dir = copyTo;
for (int i = 0; i < packages.length - 1; i++) dir = new File(dir, packages[i]);
FileUtil.copy(classFile, new File(dir, classFile.getName()));
commandLine.addParameter(copyTo.getPath());
}
commandLine.addParameter(className);
commandLine.setRedirectErrorStream(true);
return commandLine;
}
private static void checkEnvPassing(GeneralCommandLine commandLine, Map<String, String> testEnv, boolean passParentEnv) throws Exception {
commandLine.getEnvironment().putAll(testEnv);
commandLine.setPassParentEnvironment(passParentEnv);
String output = execAndGetOutput(commandLine, null);
Set<String> lines = new HashSet<String>(Arrays.asList(StringUtil.convertLineSeparators(output).split("\n")));
lines.remove("=====");
for (Map.Entry<String, String> entry : testEnv.entrySet()) {
String str = EnvPassingTest.format(entry);
assertTrue("\"" + str + "\" should be in " + lines,
lines.contains(str));
}
Map<String, String> parentEnv = System.getenv();
List<String> missed = new ArrayList<String>();
for (Map.Entry<String, String> entry : parentEnv.entrySet()) {
String str = EnvPassingTest.format(entry);
if (!lines.contains(str)) {
missed.add(str);
}
}
long pctMissed = Math.round((100.0 * missed.size()) / parentEnv.size());
if (passParentEnv && pctMissed > 25 || !passParentEnv && pctMissed < 75) {
fail("% missed: " + pctMissed + ", missed: " + missed + ", passed: " + lines);
}
}
}