vromero@1591: /* vromero@1591: * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. vromero@1591: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. vromero@1591: * vromero@1591: * This code is free software; you can redistribute it and/or modify it vromero@1591: * under the terms of the GNU General Public License version 2 only, as vromero@1591: * published by the Free Software Foundation. vromero@1591: * vromero@1591: * This code is distributed in the hope that it will be useful, but WITHOUT vromero@1591: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or vromero@1591: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License vromero@1591: * version 2 for more details (a copy is included in the LICENSE file that vromero@1591: * accompanied this code). vromero@1591: * vromero@1591: * You should have received a copy of the GNU General Public License version vromero@1591: * 2 along with this work; if not, write to the Free Software Foundation, vromero@1591: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. vromero@1591: * vromero@1591: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA vromero@1591: * or visit www.oracle.com if you need additional information or have any vromero@1591: * questions. vromero@1591: */ vromero@1591: vromero@1591: import java.io.BufferedReader; vromero@1591: import java.io.File; vromero@1591: import java.io.FileNotFoundException; vromero@1591: import java.io.FileWriter; vromero@1591: import java.io.IOException; vromero@1591: import java.io.InputStreamReader; vromero@1591: import java.io.PrintWriter; vromero@1591: import java.io.StringWriter; vromero@1591: import java.net.URI; vromero@1591: import java.nio.charset.Charset; vromero@1591: import java.nio.file.Files; vromero@1591: import java.nio.file.Path; vromero@1591: import java.nio.file.Paths; vromero@1591: import java.nio.file.StandardOpenOption; vromero@1591: import java.util.ArrayList; vromero@1591: import java.util.Arrays; vromero@1591: import java.util.Collection; vromero@1637: import java.util.Collections; vromero@1591: import java.util.EnumSet; vromero@1591: import java.util.List; vromero@1591: import java.util.Map; vromero@1591: import java.util.Set; vromero@1591: import java.util.regex.Matcher; vromero@1591: import java.util.regex.Pattern; vromero@1591: vromero@1591: import javax.tools.JavaCompiler; vromero@1591: import javax.tools.JavaFileObject; vromero@1591: import javax.tools.SimpleJavaFileObject; vromero@1591: import javax.tools.ToolProvider; vromero@1591: vromero@1591: import com.sun.source.util.JavacTask; vromero@1591: import com.sun.tools.javac.api.JavacTaskImpl; vromero@1591: vromero@1591: import sun.tools.jar.Main; vromero@1591: vromero@1591: import static java.nio.file.StandardCopyOption.*; vromero@1591: vromero@1591: /** vromero@1591: * Toolbox for jtreg tests. vromero@1591: */ vromero@1591: vromero@1591: public class ToolBox { vromero@1591: vromero@1591: public static final String lineSeparator = System.getProperty("line.separator"); vromero@1591: public static final String jdkUnderTest = System.getProperty("test.jdk"); vromero@1637: public static final Path javaBinary = Paths.get(jdkUnderTest, "bin", "java"); vromero@1637: public static final Path javacBinary = Paths.get(jdkUnderTest, "bin", "javac"); vromero@1637: vromero@1637: public static final List testToolVMOpts; vromero@1637: public static final List testVMOpts; vromero@1591: vromero@1591: private static final Charset defaultCharset = Charset.defaultCharset(); vromero@1591: vromero@1591: static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); vromero@1591: vromero@1637: static { vromero@1637: String sysProp = System.getProperty("test.tool.vm.opts"); vromero@1637: if (sysProp != null && sysProp.length() > 0) { vromero@1637: testToolVMOpts = Arrays.asList(sysProp.split("\\s+")); vromero@1637: } else { vromero@1637: testToolVMOpts = Collections.emptyList(); vromero@1637: } vromero@1637: vromero@1637: sysProp = System.getProperty("test.vm.opts"); vromero@1637: if (sysProp != null && sysProp.length() > 0) { vromero@1637: testVMOpts = Arrays.asList(sysProp.split("\\s+")); vromero@1637: } else { vromero@1637: testVMOpts = Collections.emptyList(); vromero@1637: } vromero@1637: } vromero@1637: vromero@1591: /** vromero@1591: * The expected result of command-like method execution. vromero@1591: */ vromero@1591: public enum Expect {SUCCESS, FAIL} vromero@1591: vromero@1591: enum AcceptedParams { vromero@1591: EXPECT, vromero@1591: SOURCES, vromero@1591: OPTIONS, vromero@1591: STD_OUTPUT, vromero@1591: ERR_OUTPUT, vromero@1591: EXTRA_ENV, vromero@1591: } vromero@1591: vromero@1591: enum OutputKind {STD, ERR} vromero@1591: vromero@1591: /** vromero@1591: * Helper class to abstract the processing of command's output. vromero@1591: */ vromero@1591: static abstract class WriterHelper { vromero@1591: OutputKind kind; vromero@1591: public abstract void pipeOutput(ProcessBuilder pb); vromero@1591: public abstract void readFromStream(Process p) throws IOException; vromero@1591: public abstract void addAll(Collection c) throws IOException; vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Helper class for redirecting command's output to a file. vromero@1591: */ vromero@1591: static class FileWriterHelper extends WriterHelper { vromero@1591: File file; vromero@1591: vromero@1591: FileWriterHelper(File file, OutputKind kind) { vromero@1591: this.file = file; vromero@1591: this.kind = kind; vromero@1591: } vromero@1591: vromero@1591: @Override vromero@1591: public void pipeOutput(ProcessBuilder pb) { vromero@1591: if (file != null) { vromero@1591: switch (kind) { vromero@1591: case STD: vromero@1591: pb.redirectInput(file); vromero@1591: break; vromero@1591: case ERR: vromero@1591: pb.redirectError(file); vromero@1591: break; vromero@1591: } vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: @Override vromero@1591: public void readFromStream(Process p) throws IOException {} vromero@1591: vromero@1591: @Override vromero@1591: public void addAll(Collection c) throws IOException { vromero@1591: if (file.exists()) vromero@1591: Files.write(file.toPath(), c, defaultCharset, vromero@1591: StandardOpenOption.WRITE, StandardOpenOption.APPEND); vromero@1591: else vromero@1591: Files.write(file.toPath(), c, defaultCharset); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Helper class for redirecting command's output to a String list. vromero@1591: */ vromero@1591: static class ListWriterHelper extends WriterHelper { vromero@1591: List list; vromero@1591: vromero@1591: public ListWriterHelper(List list, OutputKind kind) { vromero@1591: this.kind = kind; vromero@1591: this.list = list; vromero@1591: } vromero@1591: vromero@1591: @Override vromero@1591: public void pipeOutput(ProcessBuilder pb) {} vromero@1591: vromero@1591: @Override vromero@1591: public void readFromStream(Process p) throws IOException { vromero@1591: BufferedReader br = null; vromero@1591: switch (kind) { vromero@1591: case STD: vromero@1591: br = new BufferedReader(new InputStreamReader(p.getInputStream())); vromero@1591: break; vromero@1591: case ERR: vromero@1591: br = new BufferedReader(new InputStreamReader(p.getErrorStream())); vromero@1591: break; vromero@1591: } vromero@1591: String line; vromero@1591: while ((line = br.readLine()) != null) { vromero@1591: list.add(line); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: public void addAll(Collection c) { vromero@1591: list.addAll(c); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Simple factory class for creating a WriterHelper instance. vromero@1591: */ vromero@1591: static class WriterHelperFactory { vromero@1591: static WriterHelper make(File file, OutputKind kind) { vromero@1591: return new FileWriterHelper(file, kind); vromero@1591: } vromero@1591: vromero@1591: static WriterHelper make(List list, OutputKind kind) { vromero@1591: return new ListWriterHelper(list, kind); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A generic class for holding command's arguments. vromero@1591: */ vromero@1591: public static abstract class GenericArgs { vromero@1591: protected static List> minAcceptedParams; vromero@1591: vromero@1591: protected Set currentParams = vromero@1591: EnumSet.noneOf(AcceptedParams.class); vromero@1591: vromero@1591: protected Expect whatToExpect; vromero@1591: protected WriterHelper stdOutput; vromero@1591: protected WriterHelper errOutput; vromero@1637: protected List args = new ArrayList<>(); vromero@1637: protected String[] argsArr; vromero@1591: vromero@1591: protected GenericArgs() { vromero@1591: set(Expect.SUCCESS); vromero@1591: } vromero@1591: vromero@1591: public T set(Expect whatToExpt) { vromero@1591: currentParams.add(AcceptedParams.EXPECT); vromero@1591: this.whatToExpect = whatToExpt; vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setStdOutput(List stdOutput) { vromero@1591: currentParams.add(AcceptedParams.STD_OUTPUT); vromero@1591: this.stdOutput = WriterHelperFactory.make(stdOutput, OutputKind.STD); vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setStdOutput(File output) { vromero@1591: currentParams.add(AcceptedParams.STD_OUTPUT); vromero@1591: this.stdOutput = WriterHelperFactory.make(output, OutputKind.STD); vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setErrOutput(List errOutput) { vromero@1591: currentParams.add(AcceptedParams.ERR_OUTPUT); vromero@1591: this.errOutput = WriterHelperFactory.make(errOutput, OutputKind.ERR); vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setErrOutput(File errOutput) { vromero@1591: currentParams.add(AcceptedParams.ERR_OUTPUT); vromero@1591: this.errOutput = WriterHelperFactory.make(errOutput, OutputKind.ERR); vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setAllArgs(String... args) { vromero@1591: currentParams.add(AcceptedParams.OPTIONS); vromero@1637: this.argsArr = args; vromero@1637: return (T) this; vromero@1637: } vromero@1637: vromero@1637: vromero@1637: public T appendArgs(String... args) { vromero@1637: appendArgs(Arrays.asList(args)); vromero@1637: return (T)this; vromero@1637: } vromero@1637: vromero@1637: public T appendArgs(Path... args) { vromero@1637: if (args != null) { vromero@1637: List list = new ArrayList<>(); vromero@1637: for (int i = 0; i < args.length; i++) { vromero@1637: if (args[i] != null) { vromero@1637: list.add(args[i].toString()); vromero@1637: } vromero@1637: } vromero@1637: appendArgs(list); vromero@1637: } vromero@1637: return (T)this; vromero@1637: } vromero@1637: vromero@1637: public T appendArgs(List args) { vromero@1637: if (args != null && args.size() > 0) { vromero@1637: currentParams.add(AcceptedParams.OPTIONS); vromero@1637: for (int i = 0; i < args.size(); i++) { vromero@1637: if (args.get(i) != null) { vromero@1637: this.args.add(args.get(i)); vromero@1637: } vromero@1637: } vromero@1637: } vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setOptions(List options) { vromero@1591: currentParams.add(AcceptedParams.OPTIONS); vromero@1637: this.args = options; vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public T setOptions(String... options) { vromero@1591: currentParams.add(AcceptedParams.OPTIONS); vromero@1637: this.args = Arrays.asList(options); vromero@1591: return (T)this; vromero@1591: } vromero@1591: vromero@1591: public boolean hasMinParams() { vromero@1591: for (Set minSet : minAcceptedParams) { vromero@1591: if (currentParams.containsAll(minSet)) { vromero@1591: return true; vromero@1591: } vromero@1591: } vromero@1591: return false; vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A more specific class for holding javac-like command's arguments. vromero@1591: */ vromero@1591: public static class JavaToolArgs extends GenericArgs { vromero@1591: vromero@1591: static { vromero@1591: minAcceptedParams = new ArrayList<>(); vromero@1591: minAcceptedParams.add(EnumSet.of( vromero@1591: AcceptedParams.EXPECT, AcceptedParams.OPTIONS)); vromero@1591: minAcceptedParams.add(EnumSet.of( vromero@1591: AcceptedParams.EXPECT, AcceptedParams.SOURCES)); vromero@1591: } vromero@1591: vromero@1591: protected List sources; vromero@1591: vromero@1591: public JavaToolArgs() { vromero@1591: super(); vromero@1591: } vromero@1591: vromero@1591: public JavaToolArgs(Expect whatToExpt) { vromero@1591: super.set(whatToExpt); vromero@1591: } vromero@1591: vromero@1591: public JavaToolArgs setSources(List sources) { vromero@1591: currentParams.add(AcceptedParams.SOURCES); vromero@1591: this.sources = sources; vromero@1591: return this; vromero@1591: } vromero@1591: vromero@1591: public JavaToolArgs setSources(JavaSource... sources) { vromero@1591: return setSources(Arrays.asList(sources)); vromero@1591: } vromero@1591: vromero@1591: public JavaToolArgs setSources(String... sources) { vromero@1591: List javaSrcs = new ArrayList<>(); vromero@1591: for (String source : sources) { vromero@1591: javaSrcs.add(new JavaSource(source)); vromero@1591: } vromero@1591: return setSources(javaSrcs); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A more specific class for holding any command's arguments. vromero@1591: */ vromero@1591: public static class AnyToolArgs extends GenericArgs { vromero@1591: vromero@1591: static { vromero@1591: minAcceptedParams = new ArrayList<>(); vromero@1591: minAcceptedParams.add(EnumSet.of( vromero@1591: AcceptedParams.EXPECT, AcceptedParams.OPTIONS)); vromero@1591: } vromero@1591: vromero@1591: Map extraEnv; vromero@1591: vromero@1591: public AnyToolArgs() { vromero@1591: super(); vromero@1591: } vromero@1591: vromero@1591: public AnyToolArgs(Expect whatToExpt) { vromero@1591: set(whatToExpt); vromero@1591: } vromero@1591: vromero@1591: public AnyToolArgs set(Map extraEnv) { vromero@1591: currentParams.add(AcceptedParams.EXTRA_ENV); vromero@1591: this.extraEnv = extraEnv; vromero@1591: return this; vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Custom exception for bad command execution. vromero@1591: */ vromero@1591: public static class CommandExecutionException extends Exception { vromero@1591: CommandExecutionException(List command, Expect whatToExpt) { vromero@1591: super(createMessage(command, whatToExpt)); vromero@1591: } vromero@1591: vromero@1591: CommandExecutionException(Expect whatToExpt, String... command) { vromero@1591: this(Arrays.asList(command), whatToExpt); vromero@1591: } vromero@1591: vromero@1591: private static String createMessage(List command, Expect whatToExpt) { vromero@1591: StringBuilder sb = new StringBuilder().append("Command : "); vromero@1591: sb.append(command.toString()).append(lineSeparator); vromero@1591: switch (whatToExpt) { vromero@1591: case SUCCESS: vromero@1591: sb.append(" has unexpectedly failed"); vromero@1591: break; vromero@1591: case FAIL: vromero@1591: sb.append(" has been unexpectedly successful"); vromero@1591: break; vromero@1591: } vromero@1591: return sb.toString(); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Custom exception for not equal resources. vromero@1591: */ vromero@1591: public static class ResourcesNotEqualException extends Exception { vromero@1637: public ResourcesNotEqualException(List res1, List res2) { vromero@1637: super(createMessage(res1, res2)); vromero@1637: } vromero@1637: vromero@1637: public ResourcesNotEqualException(String line1, String line2) { vromero@1637: super(createMessage(line1, line2)); vromero@1591: } vromero@1591: vromero@1591: public ResourcesNotEqualException(Path path1, Path path2) { vromero@1591: super(createMessage(path1, path2)); vromero@1591: } vromero@1591: vromero@1591: private static String createMessage(Path path1, Path path2) { vromero@1591: return new StringBuilder() vromero@1591: .append("The resources provided for comparison in paths \n") vromero@1591: .append(path1.toString()).append(" and \n") vromero@1591: .append(path2.toString()).append("are different").toString(); vromero@1591: } vromero@1591: vromero@1637: private static String createMessage(String line1, String line2) { vromero@1637: return new StringBuilder() vromero@1637: .append("The resources provided for comparison are different at lines: \n") vromero@1637: .append(line1).append(" and \n") vromero@1637: .append(line2).toString(); vromero@1637: } vromero@1637: vromero@1637: private static String createMessage(List res1, List res2) { vromero@1637: return new StringBuilder() vromero@1637: .append("The resources provided for comparison are different: \n") vromero@1637: .append("Resource 1 is: ").append(res1).append("\n and \n") vromero@1637: .append("Resource 2 is: ").append(res2).append("\n").toString(); vromero@1637: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A javac compiler caller method. vromero@1591: */ vromero@1591: public static int javac(JavaToolArgs params) vromero@1591: throws CommandExecutionException, IOException { vromero@1591: if (params.hasMinParams()) { vromero@1637: if (params.argsArr != null) { vromero@1591: return genericJavaCMD(JavaCMD.JAVAC, params); vromero@1591: } else { vromero@1591: return genericJavaCMD(JavaCMD.JAVAC_API, params); vromero@1591: } vromero@1591: } vromero@1591: throw new AssertionError("javac command has been invoked with less parameters than needed"); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A javap calling method. vromero@1591: */ vromero@1591: public static String javap(JavaToolArgs params) vromero@1591: throws CommandExecutionException, IOException { vromero@1591: if (params.hasMinParams()) { vromero@1591: List list = new ArrayList<>(); vromero@1591: params.setErrOutput(list); vromero@1591: genericJavaCMD(JavaCMD.JAVAP, params); vromero@1591: return listToString(list); vromero@1591: } vromero@1591: throw new AssertionError("javap command has been invoked with less parameters than needed"); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A javah calling method. vromero@1591: */ vromero@1591: public static int javah(JavaToolArgs params) vromero@1591: throws CommandExecutionException, IOException { vromero@1591: if (params.hasMinParams()) { vromero@1591: return genericJavaCMD(JavaCMD.JAVAH, params); vromero@1591: } vromero@1591: throw new AssertionError("javah command has been invoked with less parameters than needed"); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A enum class for langtools commands. vromero@1591: */ vromero@1591: enum JavaCMD { vromero@1591: JAVAC { vromero@1591: @Override vromero@1591: int run(JavaToolArgs params, PrintWriter pw) { vromero@1637: return com.sun.tools.javac.Main.compile(params.argsArr, pw); vromero@1591: } vromero@1591: }, vromero@1591: JAVAC_API { vromero@1591: @Override vromero@1591: int run(JavaToolArgs params, PrintWriter pw) { vromero@1591: JavacTask ct = (JavacTask)comp.getTask(pw, null, null, vromero@1637: params.args, null, params.sources); vromero@1591: return ((JavacTaskImpl)ct).doCall().exitCode; vromero@1591: } vromero@1591: vromero@1591: @Override vromero@1591: String getName() { vromero@1591: return "javac"; vromero@1591: } vromero@1591: vromero@1591: @Override vromero@1591: List getExceptionMsgContent(JavaToolArgs params) { vromero@1591: List result = super.getExceptionMsgContent(params); vromero@1591: for (JavaFileObject source : params.sources) { vromero@1591: if (source instanceof JavaSource) { vromero@1591: result.add(((JavaSource)source).name); vromero@1591: } vromero@1591: } vromero@1591: return result; vromero@1591: } vromero@1591: }, vromero@1591: JAVAH { vromero@1591: @Override vromero@1591: int run(JavaToolArgs params, PrintWriter pw) { vromero@1637: return com.sun.tools.javah.Main.run(params.argsArr, pw); vromero@1591: } vromero@1591: }, vromero@1591: JAVAP { vromero@1591: @Override vromero@1591: int run(JavaToolArgs params, PrintWriter pw) { vromero@1637: return com.sun.tools.javap.Main.run(params.argsArr, pw); vromero@1591: } vromero@1591: }; vromero@1591: vromero@1591: abstract int run(JavaToolArgs params, PrintWriter pw); vromero@1591: vromero@1591: String getName() { vromero@1591: return this.name().toLowerCase(); vromero@1591: } vromero@1591: vromero@1591: List getExceptionMsgContent(JavaToolArgs params) { vromero@1591: List result = new ArrayList<>(); vromero@1591: result.add(getName()); vromero@1637: result.addAll(params.argsArr != null ? vromero@1637: Arrays.asList(params.argsArr) : vromero@1637: params.args); vromero@1591: return result; vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A helper method for executing langtools commands. vromero@1591: */ vromero@1591: private static int genericJavaCMD( vromero@1591: JavaCMD cmd, vromero@1591: JavaToolArgs params) vromero@1591: throws CommandExecutionException, IOException { vromero@1591: int rc = 0; vromero@1591: StringWriter sw = null; vromero@1591: try (PrintWriter pw = (params.errOutput == null) ? vromero@1591: null : new PrintWriter(sw = new StringWriter())) { vromero@1591: rc = cmd.run(params, pw); vromero@1591: } vromero@1591: String out = (sw == null) ? null : sw.toString(); vromero@1591: vromero@1591: if (params.errOutput != null && (out != null) && !out.isEmpty()) { vromero@1637: params.errOutput.addAll(splitLines(out, lineSeparator)); vromero@1591: } vromero@1591: vromero@1591: if ( (rc == 0 && params.whatToExpect == Expect.SUCCESS) || vromero@1591: (rc != 0 && params.whatToExpect == Expect.FAIL) ) { vromero@1591: return rc; vromero@1591: } vromero@1591: vromero@1591: throw new CommandExecutionException(cmd.getExceptionMsgContent(params), vromero@1591: params.whatToExpect); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A jar calling method. vromero@1591: */ vromero@1591: public static boolean jar(String... params) throws CommandExecutionException { vromero@1591: Main jarGenerator = new Main(System.out, System.err, "jar"); vromero@1591: boolean result = jarGenerator.run(params); vromero@1591: if (!result) { vromero@1591: List command = new ArrayList<>(); vromero@1591: command.add("jar"); vromero@1591: command.addAll(Arrays.asList(params)); vromero@1591: throw new CommandExecutionException(command, Expect.SUCCESS); vromero@1591: } vromero@1591: return result; vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A general command calling method. vromero@1591: */ vromero@1591: public static int executeCommand(AnyToolArgs params) vromero@1591: throws CommandExecutionException, IOException, InterruptedException { vromero@1591: if (params.hasMinParams()) { vromero@1637: List cmd = (params.args != null) ? vromero@1637: params.args : vromero@1637: Arrays.asList(params.argsArr); vromero@1591: return executeCommand(cmd, params.extraEnv, params.stdOutput, vromero@1591: params.errOutput, params.whatToExpect); vromero@1591: } vromero@1591: throw new AssertionError("command has been invoked with less parameters than needed"); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A helper method for calling a general command. vromero@1591: */ vromero@1591: private static int executeCommand( vromero@1591: List command, vromero@1591: Map extraEnv, vromero@1591: WriterHelper stdOutput, vromero@1591: WriterHelper errOutput, vromero@1591: Expect whatToExpt) vromero@1591: throws IOException, InterruptedException, CommandExecutionException { vromero@1591: ProcessBuilder pb = new ProcessBuilder(command); vromero@1591: vromero@1591: if (stdOutput != null) stdOutput.pipeOutput(pb); vromero@1591: if (errOutput != null) errOutput.pipeOutput(pb); vromero@1591: vromero@1591: if (extraEnv != null) { vromero@1591: pb.environment().putAll(extraEnv); vromero@1591: } vromero@1591: vromero@1591: Process p = pb.start(); vromero@1591: vromero@1591: if (stdOutput != null) stdOutput.readFromStream(p); vromero@1591: if (errOutput != null) errOutput.readFromStream(p); vromero@1591: vromero@1591: int result = p.waitFor(); vromero@1591: if ( (result == 0 && whatToExpt == Expect.SUCCESS) || vromero@1591: (result != 0 && whatToExpt == Expect.FAIL) ) { vromero@1591: return result; vromero@1591: } vromero@1591: vromero@1591: throw new CommandExecutionException(command, whatToExpt); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * This set of methods can be used instead of diff when the only needed vromero@1591: * result is the equality or inequality of the two given resources. vromero@1591: * vromero@1591: * A resource can be a file or a String list. vromero@1591: */ vromero@1591: public static void compareLines(Path aPath, Path otherPath, String encoding) vromero@1591: throws FileNotFoundException, IOException, ResourcesNotEqualException { vromero@1591: compareLines(aPath, otherPath, encoding, false); vromero@1591: } vromero@1591: vromero@1591: public static void compareLines( vromero@1591: Path aPath, Path otherPath, String encoding, boolean trim) vromero@1591: throws FileNotFoundException, IOException, ResourcesNotEqualException { vromero@1591: Charset charset = encoding != null ? vromero@1591: Charset.forName(encoding) : vromero@1591: defaultCharset; vromero@1591: List list1 = Files.readAllLines(aPath, charset); vromero@1591: List list2 = Files.readAllLines(otherPath, charset); vromero@1591: compareLines(list1, list2, trim); vromero@1591: } vromero@1591: vromero@1591: public static void compareLines(Path path, List strings, String encoding) vromero@1591: throws FileNotFoundException, IOException, ResourcesNotEqualException { vromero@1591: compareLines(path, strings, encoding, false); vromero@1591: } vromero@1591: vromero@1591: public static void compareLines(Path path, List strings, vromero@1591: String encoding, boolean trim) vromero@1591: throws FileNotFoundException, IOException, ResourcesNotEqualException { vromero@1591: Charset charset = encoding != null ? vromero@1591: Charset.forName(encoding) : vromero@1591: defaultCharset; vromero@1591: List list = Files.readAllLines(path, charset); vromero@1591: compareLines(list, strings, trim); vromero@1591: } vromero@1591: vromero@1591: public static void compareLines(List list1, List list2) vromero@1591: throws ResourcesNotEqualException { vromero@1591: compareLines(list1, list2, false); vromero@1591: } vromero@1591: vromero@1591: public static void compareLines(List list1, vromero@1591: List list2, boolean trim) throws ResourcesNotEqualException { vromero@1591: if ((list1 == list2) || (list1 == null && list2 == null)) return; vromero@1591: if (list1.size() != list2.size()) vromero@1637: throw new ResourcesNotEqualException(list1, list2); vromero@1591: int i = 0; vromero@1591: int j = 0; vromero@1591: while (i < list1.size() && vromero@1591: j < list2.size() && vromero@1591: equals(list1.get(i), list2.get(j), trim)) { vromero@1591: i++; j++; vromero@1591: } vromero@1591: if (!(i == list1.size() && j == list2.size())) vromero@1637: throw new ResourcesNotEqualException(list1, list2); vromero@1591: } vromero@1591: vromero@1591: private static boolean equals(String s1, String s2, boolean trim) { vromero@1591: return (trim ? s1.trim().equals(s2.trim()) : s1.equals(s2)); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A set of simple grep-like methods, looks for regExpr in text. vromero@1591: * The content of text is split using the new line character as a pattern vromero@1591: * and later the regExpr is seek in every split line. If a match is found, vromero@1591: * the whole line is added to the result. vromero@1591: */ vromero@1637: public static List grep(String regExpr, String text, String sep) { vromero@1637: return grep(regExpr, splitLines(text, sep)); vromero@1591: } vromero@1591: vromero@1591: public static List grep(String regExpr, List text) { vromero@1591: List result = new ArrayList<>(); vromero@1591: Pattern pattern = Pattern.compile(regExpr); vromero@1591: for (String s : text) { vromero@1591: if (pattern.matcher(s).find()) { vromero@1591: result.add(s); vromero@1591: } vromero@1591: } vromero@1591: return result; vromero@1591: } vromero@1591: vromero@1591: public static List grep(String regExpr, File f) vromero@1591: throws IOException { vromero@1591: List lines = Files.readAllLines(f.toPath(), defaultCharset); vromero@1591: return grep(regExpr, lines); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A touch-like method. vromero@1591: */ vromero@1591: public static boolean touch(String fileName) { vromero@1591: File file = new File(fileName); vromero@1591: return touch(file); vromero@1591: } vromero@1591: vromero@1591: public static boolean touch(File file) { vromero@1591: if (file.exists()) { vromero@1591: file.setLastModified(System.currentTimeMillis()); vromero@1591: return true; vromero@1591: } vromero@1591: return false; vromero@1591: } vromero@1591: vromero@1591: public static void createJavaFile(File outFile) throws IOException { vromero@1591: createJavaFile(outFile, null); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A method for creating a valid but very simple java file. vromero@1591: */ vromero@1591: public static void createJavaFile(File outFile, File superClass) vromero@1591: throws IOException { vromero@1591: String srcStr = "public class " + getSimpleName(outFile) + " "; vromero@1591: if (superClass != null) { vromero@1591: srcStr = srcStr.concat("extends " + getSimpleName(superClass) + " "); vromero@1591: } vromero@1591: srcStr = srcStr.concat("{}"); vromero@1591: try (PrintWriter ps = new PrintWriter(new FileWriter(outFile))) { vromero@1591: ps.println(srcStr); vromero@1591: } vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Creates a java file name given its source. vromero@1591: * The file is created in the working directory, creating a directory vromero@1591: * tree if there is a package declaration. vromero@1591: */ vromero@1591: public static void createJavaFileFromSource(String source) throws IOException { vromero@1591: createJavaFileFromSource(null, source); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Creates a java file name given its source. vromero@1591: * The file is created in the working directory, creating a directory vromero@1591: * tree if there is a package declaration or the argument initialPath vromero@1591: * has a valid path. vromero@1591: * vromero@1591: * e.i. if initialPath is foo/ and the source is: vromero@1591: * package bar; vromero@1591: * vromero@1591: * public class bazz {} vromero@1591: * vromero@1591: * this method will create the file foo/bar/bazz.java in the working vromero@1591: * directory. vromero@1591: */ vromero@1591: public static void createJavaFileFromSource(Path initialPath, vromero@1591: String source) throws IOException { vromero@1591: String fileName = getJavaFileNameFromSource(source); vromero@1591: String dirTree = getDirTreeFromSource(source); vromero@1591: Path path = (dirTree != null) ? vromero@1591: Paths.get(dirTree, fileName) : vromero@1591: Paths.get(fileName); vromero@1591: path = (initialPath != null) ? vromero@1591: initialPath.resolve(path): vromero@1591: path; vromero@1591: writeFile(path, source); vromero@1591: } vromero@1591: vromero@1591: static Pattern publicClassPattern = vromero@1591: Pattern.compile("public\\s+(?:class|enum|interface){1}\\s+(\\w+)"); vromero@1591: static Pattern packageClassPattern = vromero@1591: Pattern.compile("(?:class|enum|interface){1}\\s+(\\w+)"); vromero@1591: vromero@1591: /** vromero@1591: * Extracts the java file name from the class declaration. vromero@1591: * This method is intended for simple files and uses regular expressions, vromero@1591: * so comments matching the pattern can make the method fail. vromero@1591: */ vromero@1591: private static String getJavaFileNameFromSource(String source) { vromero@1591: String className = null; vromero@1591: Matcher matcher = publicClassPattern.matcher(source); vromero@1591: if (matcher.find()) { vromero@1591: className = matcher.group(1) + ".java"; vromero@1591: } else { vromero@1591: matcher = packageClassPattern.matcher(source); vromero@1591: if (matcher.find()) { vromero@1591: className = matcher.group(1) + ".java"; vromero@1591: } else { vromero@1591: throw new AssertionError("Could not extract the java class " + vromero@1591: "name from the provided source"); vromero@1591: } vromero@1591: } vromero@1591: return className; vromero@1591: } vromero@1591: vromero@1591: static Pattern packagePattern = vromero@1591: Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))"); vromero@1591: vromero@1591: /** vromero@1591: * Extracts the path from the package declaration if present. vromero@1591: * This method is intended for simple files and uses regular expressions, vromero@1591: * so comments matching the pattern can make the method fail. vromero@1591: */ vromero@1591: private static String getDirTreeFromSource(String source) { vromero@1591: Matcher matcher = packagePattern.matcher(source); vromero@1591: return matcher.find() ? vromero@1591: matcher.group(1).replace(".", File.separator) : vromero@1591: null; vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A method for creating a jar's manifest file with supplied data. vromero@1591: */ vromero@1591: public static void mkManifestWithClassPath(String mainClass, vromero@1591: String... classes) throws IOException { vromero@1591: List lines = new ArrayList<>(); vromero@1591: vromero@1591: StringBuilder sb = new StringBuilder("Class-Path: ".length() + vromero@1591: classes[0].length()).append("Class-Path: ").append(classes[0]); vromero@1591: for (int i = 1; i < classes.length; i++) { vromero@1591: sb.append(" ").append(classes[i]); vromero@1591: } vromero@1591: lines.add(sb.toString()); vromero@1591: if (mainClass != null) { vromero@1591: lines.add(new StringBuilder("Main-Class: ".length() + vromero@1591: mainClass.length()) vromero@1591: .append("Main-Class: ") vromero@1591: .append(mainClass).toString()); vromero@1591: } vromero@1591: Files.write(Paths.get("MANIFEST.MF"), lines, null); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A utility method to obtain the file name. vromero@1591: */ vromero@1591: static String getSimpleName(File inFile) { vromero@1591: return inFile.toPath().getFileName().toString(); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A method to write to a file, the directory tree is created if needed. vromero@1591: */ vromero@1591: public static File writeFile(Path path, String body) throws IOException { vromero@1591: File result; vromero@1591: if (path.getParent() != null) { vromero@1591: Files.createDirectories(path.getParent()); vromero@1591: } vromero@1591: try (FileWriter out = new FileWriter(result = path.toAbsolutePath().toFile())) { vromero@1591: out.write(body); vromero@1591: } vromero@1591: return result; vromero@1591: } vromero@1591: vromero@1591: public static File writeFile(String path, String body) throws IOException { vromero@1591: return writeFile(Paths.get(path), body); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * A rm-like method, the file is deleted only if it exists. vromero@1591: */ vromero@1591: public static void rm(Path path) throws Exception { vromero@1591: Files.deleteIfExists(path); vromero@1591: } vromero@1591: vromero@1591: public static void rm(String filename) throws Exception { vromero@1591: rm(Paths.get(filename)); vromero@1591: } vromero@1591: vromero@1591: public static void rm(File f) throws Exception { vromero@1591: rm(f.toPath()); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Copy source file to destination file. vromero@1591: */ vromero@1591: public static void copyFile(File destfile, File srcfile) vromero@1591: throws IOException { vromero@1591: copyFile(destfile.toPath(), srcfile.toPath()); vromero@1591: } vromero@1591: vromero@1591: public static void copyFile(Path destPath, Path srcPath) vromero@1591: throws IOException { vromero@1591: Files.createDirectories(destPath); vromero@1591: Files.copy(srcPath, destPath, REPLACE_EXISTING); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Splits a String using the System's line separator character as splitting point. vromero@1591: */ vromero@1637: public static List splitLines(String lines, String sep) { vromero@1637: return Arrays.asList(lines.split(sep)); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1591: * Converts a String list into one String by appending the System's line separator vromero@1591: * character after each component. vromero@1591: */ vromero@1591: private static String listToString(List lines) { vromero@1591: StringBuilder sb = new StringBuilder(); vromero@1591: for (String s : lines) { vromero@1591: sb.append(s).append(lineSeparator); vromero@1591: } vromero@1591: return sb.toString(); vromero@1591: } vromero@1591: vromero@1591: /** vromero@1637: * Returns true if the OS is a Windows version. vromero@1637: */ vromero@1637: public static boolean isWindows() { vromero@1637: String osName = System.getProperty("os.name"); vromero@1637: return osName.toUpperCase().startsWith("WINDOWS"); vromero@1637: } vromero@1637: vromero@1637: /** vromero@1591: * Class representing an in-memory java source file. It is able to extract vromero@1591: * the file name from simple source codes using regular expressions. vromero@1591: */ vromero@1591: public static class JavaSource extends SimpleJavaFileObject { vromero@1591: String source; vromero@1591: String name; vromero@1591: vromero@1591: public JavaSource(String className, String source) { vromero@1591: super(URI.create(className), vromero@1591: JavaFileObject.Kind.SOURCE); vromero@1591: this.name = className; vromero@1591: this.source = source; vromero@1591: } vromero@1591: vromero@1591: public JavaSource(String source) { vromero@1591: super(URI.create(getJavaFileNameFromSource(source)), vromero@1591: JavaFileObject.Kind.SOURCE); vromero@1591: this.name = getJavaFileNameFromSource(source); vromero@1591: this.source = source; vromero@1591: } vromero@1591: vromero@1591: @Override vromero@1591: public CharSequence getCharContent(boolean ignoreEncodingErrors) { vromero@1591: return source; vromero@1591: } vromero@1591: } vromero@1591: }