package com.google.jstestdriver.idea.execution; import com.google.common.base.Charsets; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.jstestdriver.JsTestDriverServer; import com.google.jstestdriver.idea.TestRunner; import com.google.jstestdriver.idea.config.JstdConfigFileUtils; import com.google.jstestdriver.idea.execution.generator.JstdConfigGenerator; import com.google.jstestdriver.idea.execution.settings.JstdConfigType; import com.google.jstestdriver.idea.execution.settings.JstdRunSettings; import com.google.jstestdriver.idea.execution.settings.ServerType; import com.google.jstestdriver.idea.execution.settings.TestType; import com.google.jstestdriver.idea.ui.ToolPanel; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PathUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import static com.google.common.collect.Lists.transform; import static java.io.File.pathSeparator; class JstdClientCommandLineBuilder { private static final Logger log = Logger.getInstance(TestRunnerState.class.getCanonicalName()); public static final JstdClientCommandLineBuilder INSTANCE = new JstdClientCommandLineBuilder(); private static final Function<File, String> GET_ABSOLUTE_PATH = new Function<File, String>() { @Override public String apply(File file) { return file.getAbsolutePath(); } }; private JstdClientCommandLineBuilder() { } public GeneralCommandLine buildCommandLine(JstdRunSettings runSettings, int testResultPort, List<VirtualFile> configVirtualFiles) { final Map<TestRunner.ParameterKey, String> parameters = Maps.newHashMap(); final String serverURL = runSettings.getServerType() == ServerType.INTERNAL ? "http://localhost:" + ToolPanel.serverPort : runSettings.getServerAddress(); parameters.put(TestRunner.ParameterKey.SERVER_URL, serverURL); parameters.put(TestRunner.ParameterKey.PORT, String.valueOf(testResultPort)); String joinedConfigPaths = joinConfigs(configVirtualFiles); parameters.put(TestRunner.ParameterKey.CONFIG_FILE, joinedConfigPaths); if (runSettings.getTestType() == TestType.TEST_CASE) { parameters.put(TestRunner.ParameterKey.TEST_CASE, runSettings.getTestCaseName()); } if (runSettings.getTestType() == TestType.TEST_METHOD) { parameters.put(TestRunner.ParameterKey.TEST_CASE, runSettings.getTestCaseName()); parameters.put(TestRunner.ParameterKey.TEST_METHOD, runSettings.getTestMethodName()); } return buildCommandLine(parameters); } private GeneralCommandLine buildCommandLine(Map<TestRunner.ParameterKey, String> parameters) { GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"); // uncomment this if you want to debug jsTestDriver code in the test-runner process //addParameter("-Xdebug"); //addParameter("-Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=y"); commandLine.addParameter("-cp"); commandLine.addParameter(buildClasspath()); commandLine.addParameter(TestRunner.class.getName()); for (Map.Entry<TestRunner.ParameterKey, String> param : parameters.entrySet()) { commandLine.addParameter("--" + param.getKey().name().toLowerCase() + "=" + param.getValue()); } return commandLine; } private String joinConfigs(List<VirtualFile> configs) { List<String> jstdConfigPaths = Lists.newArrayList(); for (VirtualFile config : configs) { try { String encodedPath = URLEncoder.encode(config.getPath(), Charsets.UTF_8.name()); jstdConfigPaths.add(encodedPath); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return StringUtil.join(jstdConfigPaths, ","); } @NotNull public List<VirtualFile> collectVirtualFiles(JstdRunSettings runSettings, Project project) { TestType testType = runSettings.getTestType(); List<VirtualFile> res = Collections.emptyList(); if (testType == TestType.ALL_CONFIGS_IN_DIRECTORY) { VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(new File(runSettings.getDirectory())); if (virtualFile != null) { res = collectJstdConfigFilesInDirectory(virtualFile); } } else { File configFile = extractConfigFile(project, runSettings); VirtualFile configVirtualFile = null; if (configFile != null) { configVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(configFile); } if (configVirtualFile != null) { res = Collections.singletonList(configVirtualFile); } } return res; } private File extractConfigFile(Project project, JstdRunSettings runSettings) { if (runSettings.getTestType() == TestType.CONFIG_FILE || runSettings.getConfigType() == JstdConfigType.FILE_PATH) { return new File(runSettings.getConfigFile()); } try { return JstdConfigGenerator.INSTANCE.generateTempConfig(project, new File(runSettings.getJsFilePath())); } catch (IOException ignored) { } return null; } @NotNull public List<VirtualFile> collectJstdConfigFilesInDirectory(@Nullable VirtualFile directory) { if (directory != null) { List<VirtualFile> configs = Lists.newArrayList(); collectJstdConfigs(directory, configs); return configs; } else { return Collections.emptyList(); } } private void collectJstdConfigs(VirtualFile directory, List<VirtualFile> jstdConfigs) { VirtualFile[] children = directory.getChildren(); for (VirtualFile child : children) { if (child.isDirectory()) { collectJstdConfigs(child, jstdConfigs); } else if (JstdConfigFileUtils.isJstdConfigFile(child)) { jstdConfigs.add(child); } } } private String buildClasspath() { Set<String> classpath = Sets.newHashSet(); List<File> files = getClasspath(TestRunner.class, JsTestDriverServer.class); classpath.addAll(transform(files, GET_ABSOLUTE_PATH)); return Joiner.on(pathSeparator).join(classpath); } private List<File> getClasspath(Class<?>... classList) { List<File> classpath = Lists.newArrayList(); for (Class<?> clazz : classList) { String path = PathUtil.getJarPathForClass(clazz); File file = new File(path); if (!file.exists()) { log.warn("Can't find path for " + clazz.getName()); } else { classpath.add(file.getAbsoluteFile()); } } return classpath; } }