langtools/test/tools/javac/lib/ToolBox.java
changeset 16304 475504933a2d
child 16549 1bdeedb5446c
equal deleted inserted replaced
16303:b5dca0b42963 16304:475504933a2d
       
     1 /*
       
     2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.io.BufferedReader;
       
    25 import java.io.File;
       
    26 import java.io.FileNotFoundException;
       
    27 import java.io.FileWriter;
       
    28 import java.io.IOException;
       
    29 import java.io.InputStreamReader;
       
    30 import java.io.PrintWriter;
       
    31 import java.io.StringWriter;
       
    32 import java.net.URI;
       
    33 import java.nio.charset.Charset;
       
    34 import java.nio.file.Files;
       
    35 import java.nio.file.Path;
       
    36 import java.nio.file.Paths;
       
    37 import java.nio.file.StandardOpenOption;
       
    38 import java.util.ArrayList;
       
    39 import java.util.Arrays;
       
    40 import java.util.Collection;
       
    41 import java.util.EnumSet;
       
    42 import java.util.List;
       
    43 import java.util.Map;
       
    44 import java.util.Set;
       
    45 import java.util.regex.Matcher;
       
    46 import java.util.regex.Pattern;
       
    47 
       
    48 import javax.tools.JavaCompiler;
       
    49 import javax.tools.JavaFileObject;
       
    50 import javax.tools.SimpleJavaFileObject;
       
    51 import javax.tools.ToolProvider;
       
    52 
       
    53 import com.sun.source.util.JavacTask;
       
    54 import com.sun.tools.javac.api.JavacTaskImpl;
       
    55 
       
    56 import sun.tools.jar.Main;
       
    57 
       
    58 import static java.nio.file.StandardCopyOption.*;
       
    59 
       
    60 /**
       
    61  * Toolbox for jtreg tests.
       
    62  */
       
    63 
       
    64 public class ToolBox {
       
    65 
       
    66     public static final String lineSeparator = System.getProperty("line.separator");
       
    67     public static final String jdkUnderTest = System.getProperty("test.jdk");
       
    68     public static final String testVMOpts = System.getProperty("test.tool.vm.opts");
       
    69     public static final String javaBinary = Paths.get(jdkUnderTest, "bin", "java").toString();
       
    70     //why this one private. Because the function which provide also the test options should be used
       
    71     private static final String javacBinary = Paths.get(jdkUnderTest, "bin", "javac").toString();
       
    72 
       
    73     private static final Charset defaultCharset = Charset.defaultCharset();
       
    74 
       
    75     static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
       
    76 
       
    77     /**
       
    78      * The expected result of command-like method execution.
       
    79      */
       
    80     public enum Expect {SUCCESS, FAIL}
       
    81 
       
    82     enum AcceptedParams {
       
    83         EXPECT,
       
    84         SOURCES,
       
    85         OPTIONS,
       
    86         STD_OUTPUT,
       
    87         ERR_OUTPUT,
       
    88         EXTRA_ENV,
       
    89     }
       
    90 
       
    91     enum OutputKind {STD, ERR}
       
    92 
       
    93     /**
       
    94      * Helper class to abstract the processing of command's output.
       
    95      */
       
    96     static abstract class WriterHelper {
       
    97         OutputKind kind;
       
    98         public abstract void pipeOutput(ProcessBuilder pb);
       
    99         public abstract void readFromStream(Process p) throws IOException;
       
   100         public abstract void addAll(Collection<? extends String> c) throws IOException;
       
   101     }
       
   102 
       
   103     /**
       
   104      * Helper class for redirecting command's output to a file.
       
   105      */
       
   106     static class FileWriterHelper extends WriterHelper {
       
   107         File file;
       
   108 
       
   109         FileWriterHelper(File file, OutputKind kind) {
       
   110             this.file = file;
       
   111             this.kind = kind;
       
   112         }
       
   113 
       
   114         @Override
       
   115         public void pipeOutput(ProcessBuilder pb) {
       
   116             if (file != null) {
       
   117                 switch (kind) {
       
   118                     case STD:
       
   119                         pb.redirectInput(file);
       
   120                         break;
       
   121                     case ERR:
       
   122                         pb.redirectError(file);
       
   123                         break;
       
   124                 }
       
   125             }
       
   126         }
       
   127 
       
   128         @Override
       
   129         public void readFromStream(Process p) throws IOException {}
       
   130 
       
   131         @Override
       
   132         public void addAll(Collection<? extends String> c) throws IOException {
       
   133             if (file.exists())
       
   134                 Files.write(file.toPath(), c, defaultCharset,
       
   135                         StandardOpenOption.WRITE, StandardOpenOption.APPEND);
       
   136             else
       
   137                 Files.write(file.toPath(), c, defaultCharset);
       
   138         }
       
   139     }
       
   140 
       
   141     /**
       
   142      * Helper class for redirecting command's output to a String list.
       
   143      */
       
   144     static class ListWriterHelper extends WriterHelper {
       
   145         List<String> list;
       
   146 
       
   147         public ListWriterHelper(List<String> list, OutputKind kind) {
       
   148             this.kind = kind;
       
   149             this.list = list;
       
   150         }
       
   151 
       
   152         @Override
       
   153         public void pipeOutput(ProcessBuilder pb) {}
       
   154 
       
   155         @Override
       
   156         public void readFromStream(Process p) throws IOException {
       
   157             BufferedReader br = null;
       
   158             switch (kind) {
       
   159                 case STD:
       
   160                     br = new BufferedReader(new InputStreamReader(p.getInputStream()));
       
   161                     break;
       
   162                 case ERR:
       
   163                     br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
       
   164                     break;
       
   165             }
       
   166             String line;
       
   167             while ((line = br.readLine()) != null) {
       
   168                 list.add(line);
       
   169             }
       
   170         }
       
   171 
       
   172         public void addAll(Collection<? extends String> c) {
       
   173             list.addAll(c);
       
   174         }
       
   175     }
       
   176 
       
   177     /**
       
   178      * Simple factory class for creating a WriterHelper instance.
       
   179      */
       
   180     static class WriterHelperFactory {
       
   181         static WriterHelper make(File file, OutputKind kind) {
       
   182             return new FileWriterHelper(file, kind);
       
   183         }
       
   184 
       
   185         static WriterHelper make(List<String> list, OutputKind kind) {
       
   186             return new ListWriterHelper(list, kind);
       
   187         }
       
   188     }
       
   189 
       
   190     /**
       
   191      * A generic class for holding command's arguments.
       
   192      */
       
   193     public static abstract class GenericArgs <T extends GenericArgs> {
       
   194         protected static List<Set<AcceptedParams>> minAcceptedParams;
       
   195 
       
   196         protected Set<AcceptedParams> currentParams =
       
   197                 EnumSet.<AcceptedParams>noneOf(AcceptedParams.class);
       
   198 
       
   199         protected Expect whatToExpect;
       
   200         protected WriterHelper stdOutput;
       
   201         protected WriterHelper errOutput;
       
   202         protected List<String> options;
       
   203         protected String[] optionsArr;
       
   204 
       
   205         protected GenericArgs() {
       
   206             set(Expect.SUCCESS);
       
   207         }
       
   208 
       
   209         public T set(Expect whatToExpt) {
       
   210             currentParams.add(AcceptedParams.EXPECT);
       
   211             this.whatToExpect = whatToExpt;
       
   212             return (T)this;
       
   213         }
       
   214 
       
   215         public T setStdOutput(List<String> stdOutput) {
       
   216             currentParams.add(AcceptedParams.STD_OUTPUT);
       
   217             this.stdOutput = WriterHelperFactory.make(stdOutput, OutputKind.STD);
       
   218             return (T)this;
       
   219         }
       
   220 
       
   221         public T setStdOutput(File output) {
       
   222             currentParams.add(AcceptedParams.STD_OUTPUT);
       
   223             this.stdOutput = WriterHelperFactory.make(output, OutputKind.STD);
       
   224             return (T)this;
       
   225         }
       
   226 
       
   227         public T setErrOutput(List<String> errOutput) {
       
   228             currentParams.add(AcceptedParams.ERR_OUTPUT);
       
   229             this.errOutput = WriterHelperFactory.make(errOutput, OutputKind.ERR);
       
   230             return (T)this;
       
   231         }
       
   232 
       
   233         public T setErrOutput(File errOutput) {
       
   234             currentParams.add(AcceptedParams.ERR_OUTPUT);
       
   235             this.errOutput = WriterHelperFactory.make(errOutput, OutputKind.ERR);
       
   236             return (T)this;
       
   237         }
       
   238 
       
   239         public T setAllArgs(String... args) {
       
   240             currentParams.add(AcceptedParams.OPTIONS);
       
   241             this.optionsArr = args;
       
   242             return (T)this;
       
   243         }
       
   244 
       
   245         public T setOptions(List<String> options) {
       
   246             currentParams.add(AcceptedParams.OPTIONS);
       
   247             this.options = options;
       
   248             return (T)this;
       
   249         }
       
   250 
       
   251         public T setOptions(String... options) {
       
   252             currentParams.add(AcceptedParams.OPTIONS);
       
   253             this.options = Arrays.asList(options);
       
   254             return (T)this;
       
   255         }
       
   256 
       
   257         public boolean hasMinParams() {
       
   258             for (Set<AcceptedParams> minSet : minAcceptedParams) {
       
   259                 if (currentParams.containsAll(minSet)) {
       
   260                     return true;
       
   261                 }
       
   262             }
       
   263             return false;
       
   264         }
       
   265     }
       
   266 
       
   267     /**
       
   268      * A more specific class for holding javac-like command's arguments.
       
   269      */
       
   270     public static class JavaToolArgs extends GenericArgs<JavaToolArgs> {
       
   271 
       
   272         static {
       
   273             minAcceptedParams = new ArrayList<>();
       
   274             minAcceptedParams.add(EnumSet.<AcceptedParams>of(
       
   275                     AcceptedParams.EXPECT, AcceptedParams.OPTIONS));
       
   276             minAcceptedParams.add(EnumSet.<AcceptedParams>of(
       
   277                     AcceptedParams.EXPECT, AcceptedParams.SOURCES));
       
   278         }
       
   279 
       
   280         protected List<? extends JavaFileObject> sources;
       
   281 
       
   282         public JavaToolArgs() {
       
   283             super();
       
   284         }
       
   285 
       
   286         public JavaToolArgs(Expect whatToExpt) {
       
   287             super.set(whatToExpt);
       
   288         }
       
   289 
       
   290         public JavaToolArgs setSources(List<? extends JavaFileObject> sources) {
       
   291             currentParams.add(AcceptedParams.SOURCES);
       
   292             this.sources = sources;
       
   293             return this;
       
   294         }
       
   295 
       
   296         public JavaToolArgs setSources(JavaSource... sources) {
       
   297             return setSources(Arrays.asList(sources));
       
   298         }
       
   299 
       
   300         public JavaToolArgs setSources(String... sources) {
       
   301             List<JavaSource> javaSrcs = new ArrayList<>();
       
   302             for (String source : sources) {
       
   303                 javaSrcs.add(new JavaSource(source));
       
   304             }
       
   305             return setSources(javaSrcs);
       
   306         }
       
   307     }
       
   308 
       
   309     /**
       
   310      * A more specific class for holding any command's arguments.
       
   311      */
       
   312     public static class AnyToolArgs extends GenericArgs<AnyToolArgs> {
       
   313 
       
   314         static {
       
   315             minAcceptedParams = new ArrayList<>();
       
   316             minAcceptedParams.add(EnumSet.<AcceptedParams>of(
       
   317                     AcceptedParams.EXPECT, AcceptedParams.OPTIONS));
       
   318         }
       
   319 
       
   320         Map<String, String> extraEnv;
       
   321 
       
   322         public AnyToolArgs() {
       
   323             super();
       
   324         }
       
   325 
       
   326         public AnyToolArgs(Expect whatToExpt) {
       
   327             set(whatToExpt);
       
   328         }
       
   329 
       
   330         public AnyToolArgs set(Map<String, String> extraEnv) {
       
   331             currentParams.add(AcceptedParams.EXTRA_ENV);
       
   332             this.extraEnv = extraEnv;
       
   333             return this;
       
   334         }
       
   335     }
       
   336 
       
   337     /**
       
   338      * Custom exception for bad command execution.
       
   339      */
       
   340     public static class CommandExecutionException extends Exception {
       
   341         CommandExecutionException(List<String> command, Expect whatToExpt) {
       
   342             super(createMessage(command, whatToExpt));
       
   343         }
       
   344 
       
   345         CommandExecutionException(Expect whatToExpt, String... command) {
       
   346             this(Arrays.asList(command), whatToExpt);
       
   347         }
       
   348 
       
   349         private static String createMessage(List<String> command, Expect whatToExpt) {
       
   350             StringBuilder sb = new StringBuilder().append("Command : ");
       
   351             sb.append(command.toString()).append(lineSeparator);
       
   352             switch (whatToExpt) {
       
   353                 case SUCCESS:
       
   354                     sb.append("    has unexpectedly failed");
       
   355                     break;
       
   356                 case FAIL:
       
   357                     sb.append("    has been unexpectedly successful");
       
   358                     break;
       
   359             }
       
   360             return sb.toString();
       
   361         }
       
   362     }
       
   363 
       
   364     /**
       
   365      * Custom exception for not equal resources.
       
   366      */
       
   367     public static class ResourcesNotEqualException extends Exception {
       
   368         public ResourcesNotEqualException() {
       
   369             super("The resources provided for comparison are different");
       
   370         }
       
   371 
       
   372         public ResourcesNotEqualException(Path path1, Path path2) {
       
   373             super(createMessage(path1, path2));
       
   374         }
       
   375 
       
   376         private static String createMessage(Path path1, Path path2) {
       
   377             return new StringBuilder()
       
   378                     .append("The resources provided for comparison in paths \n")
       
   379                     .append(path1.toString()).append(" and \n")
       
   380                     .append(path2.toString()).append("are different").toString();
       
   381         }
       
   382     }
       
   383 
       
   384     /**
       
   385      * Method to get the a path to the javac command available at the jdk being
       
   386      * tested along with the test vm options.
       
   387      * @return a String[] with the two components mentioned.
       
   388      */
       
   389     public static String[] getJavacBin() {
       
   390         return new String[]{javacBinary, testVMOpts};
       
   391     }
       
   392 
       
   393     /**
       
   394      * A javac compiler caller method.
       
   395      */
       
   396     public static int javac(JavaToolArgs params)
       
   397             throws CommandExecutionException, IOException {
       
   398         if (params.hasMinParams()) {
       
   399             if (params.optionsArr != null) {
       
   400                 return genericJavaCMD(JavaCMD.JAVAC, params);
       
   401             } else {
       
   402                 return genericJavaCMD(JavaCMD.JAVAC_API, params);
       
   403             }
       
   404         }
       
   405         throw new AssertionError("javac command has been invoked with less parameters than needed");
       
   406     }
       
   407 
       
   408     /**
       
   409      * A javap calling method.
       
   410      */
       
   411     public static String javap(JavaToolArgs params)
       
   412             throws CommandExecutionException, IOException {
       
   413         if (params.hasMinParams()) {
       
   414             List<String> list = new ArrayList<>();
       
   415             params.setErrOutput(list);
       
   416             genericJavaCMD(JavaCMD.JAVAP, params);
       
   417             return listToString(list);
       
   418         }
       
   419         throw new AssertionError("javap command has been invoked with less parameters than needed");
       
   420     }
       
   421 
       
   422     /**
       
   423      * A javah calling method.
       
   424      */
       
   425     public static int javah(JavaToolArgs params)
       
   426             throws CommandExecutionException, IOException {
       
   427         if (params.hasMinParams()) {
       
   428             return genericJavaCMD(JavaCMD.JAVAH, params);
       
   429         }
       
   430         throw new AssertionError("javah command has been invoked with less parameters than needed");
       
   431     }
       
   432 
       
   433     /**
       
   434      * A enum class for langtools commands.
       
   435      */
       
   436     enum JavaCMD {
       
   437         JAVAC {
       
   438             @Override
       
   439             int run(JavaToolArgs params, PrintWriter pw) {
       
   440                 return com.sun.tools.javac.Main.compile(params.optionsArr, pw);
       
   441             }
       
   442         },
       
   443         JAVAC_API {
       
   444             @Override
       
   445             int run(JavaToolArgs params, PrintWriter pw) {
       
   446                 JavacTask ct = (JavacTask)comp.getTask(pw, null, null,
       
   447                         params.options, null, params.sources);
       
   448                 return ((JavacTaskImpl)ct).doCall().exitCode;
       
   449             }
       
   450 
       
   451             @Override
       
   452             String getName() {
       
   453                 return "javac";
       
   454             }
       
   455 
       
   456             @Override
       
   457             List<String> getExceptionMsgContent(JavaToolArgs params) {
       
   458                 List<String> result = super.getExceptionMsgContent(params);
       
   459                 for (JavaFileObject source : params.sources) {
       
   460                     if (source instanceof JavaSource) {
       
   461                         result.add(((JavaSource)source).name);
       
   462                     }
       
   463                 }
       
   464                 return result;
       
   465             }
       
   466         },
       
   467         JAVAH {
       
   468             @Override
       
   469             int run(JavaToolArgs params, PrintWriter pw) {
       
   470                 return com.sun.tools.javah.Main.run(params.optionsArr, pw);
       
   471             }
       
   472         },
       
   473         JAVAP {
       
   474             @Override
       
   475             int run(JavaToolArgs params, PrintWriter pw) {
       
   476                 return com.sun.tools.javap.Main.run(params.optionsArr, pw);
       
   477             }
       
   478         };
       
   479 
       
   480         abstract int run(JavaToolArgs params, PrintWriter pw);
       
   481 
       
   482         String getName() {
       
   483             return this.name().toLowerCase();
       
   484         }
       
   485 
       
   486         List<String> getExceptionMsgContent(JavaToolArgs params) {
       
   487             List<String> result = new ArrayList<>();
       
   488             result.add(getName());
       
   489             result.addAll(params.optionsArr != null ?
       
   490                     Arrays.asList(params.optionsArr) :
       
   491                     params.options);
       
   492             return result;
       
   493         }
       
   494     }
       
   495 
       
   496     /**
       
   497      * A helper method for executing langtools commands.
       
   498      */
       
   499     private static int genericJavaCMD(
       
   500             JavaCMD cmd,
       
   501             JavaToolArgs params)
       
   502             throws CommandExecutionException, IOException {
       
   503         int rc = 0;
       
   504         StringWriter sw = null;
       
   505         try (PrintWriter pw = (params.errOutput == null) ?
       
   506                 null : new PrintWriter(sw = new StringWriter())) {
       
   507             rc = cmd.run(params, pw);
       
   508         }
       
   509         String out = (sw == null) ? null : sw.toString();
       
   510 
       
   511         if (params.errOutput != null && (out != null) && !out.isEmpty()) {
       
   512             params.errOutput.addAll(splitLines(out));
       
   513         }
       
   514 
       
   515         if ( (rc == 0 && params.whatToExpect == Expect.SUCCESS) ||
       
   516              (rc != 0 && params.whatToExpect == Expect.FAIL) ) {
       
   517             return rc;
       
   518         }
       
   519 
       
   520         throw new CommandExecutionException(cmd.getExceptionMsgContent(params),
       
   521                 params.whatToExpect);
       
   522     }
       
   523 
       
   524     /**
       
   525      * A jar calling method.
       
   526      */
       
   527     public static boolean jar(String... params) throws CommandExecutionException {
       
   528         Main jarGenerator = new Main(System.out, System.err, "jar");
       
   529         boolean result = jarGenerator.run(params);
       
   530         if (!result) {
       
   531             List<String> command = new ArrayList<>();
       
   532             command.add("jar");
       
   533             command.addAll(Arrays.asList(params));
       
   534             throw new CommandExecutionException(command, Expect.SUCCESS);
       
   535         }
       
   536         return result;
       
   537     }
       
   538 
       
   539     /**
       
   540      * A general command calling method.
       
   541      */
       
   542     public static int executeCommand(AnyToolArgs params)
       
   543             throws CommandExecutionException, IOException, InterruptedException {
       
   544         if (params.hasMinParams()) {
       
   545             List<String> cmd = (params.options != null) ?
       
   546                     params.options :
       
   547                     Arrays.asList(params.optionsArr);
       
   548             return executeCommand(cmd, params.extraEnv, params.stdOutput,
       
   549                     params.errOutput, params.whatToExpect);
       
   550         }
       
   551         throw new AssertionError("command has been invoked with less parameters than needed");
       
   552     }
       
   553 
       
   554     /**
       
   555      * A helper method for calling a general command.
       
   556      */
       
   557     private static int executeCommand(
       
   558             List<String> command,
       
   559             Map<String, String> extraEnv,
       
   560             WriterHelper stdOutput,
       
   561             WriterHelper errOutput,
       
   562             Expect whatToExpt)
       
   563             throws IOException, InterruptedException, CommandExecutionException {
       
   564         ProcessBuilder pb = new ProcessBuilder(command);
       
   565 
       
   566         if (stdOutput != null) stdOutput.pipeOutput(pb);
       
   567         if (errOutput != null) errOutput.pipeOutput(pb);
       
   568 
       
   569         if (extraEnv != null) {
       
   570             pb.environment().putAll(extraEnv);
       
   571         }
       
   572 
       
   573         Process p = pb.start();
       
   574 
       
   575         if (stdOutput != null) stdOutput.readFromStream(p);
       
   576         if (errOutput != null) errOutput.readFromStream(p);
       
   577 
       
   578         int result = p.waitFor();
       
   579         if ( (result == 0 && whatToExpt == Expect.SUCCESS) ||
       
   580              (result != 0 && whatToExpt == Expect.FAIL) ) {
       
   581             return result;
       
   582         }
       
   583 
       
   584         throw new CommandExecutionException(command, whatToExpt);
       
   585     }
       
   586 
       
   587     /**
       
   588      * This set of methods can be used instead of diff when the only needed
       
   589      * result is the equality or inequality of the two given resources.
       
   590      *
       
   591      * A resource can be a file or a String list.
       
   592      */
       
   593     public static void compareLines(Path aPath, Path otherPath, String encoding)
       
   594             throws FileNotFoundException, IOException, ResourcesNotEqualException {
       
   595         compareLines(aPath, otherPath, encoding, false);
       
   596     }
       
   597 
       
   598     public static void compareLines(
       
   599             Path aPath, Path otherPath, String encoding, boolean trim)
       
   600             throws FileNotFoundException, IOException, ResourcesNotEqualException {
       
   601         Charset charset = encoding != null ?
       
   602                 Charset.forName(encoding) :
       
   603                 defaultCharset;
       
   604         List<String> list1 = Files.readAllLines(aPath, charset);
       
   605         List<String> list2 = Files.readAllLines(otherPath, charset);
       
   606         compareLines(list1, list2, trim);
       
   607     }
       
   608 
       
   609     public static void compareLines(Path path, List<String> strings, String encoding)
       
   610             throws FileNotFoundException, IOException, ResourcesNotEqualException {
       
   611         compareLines(path, strings, encoding, false);
       
   612     }
       
   613 
       
   614     public static void compareLines(Path path, List<String> strings,
       
   615             String encoding, boolean trim)
       
   616             throws FileNotFoundException, IOException, ResourcesNotEqualException {
       
   617         Charset charset = encoding != null ?
       
   618                 Charset.forName(encoding) :
       
   619                 defaultCharset;
       
   620         List<String> list = Files.readAllLines(path, charset);
       
   621         compareLines(list, strings, trim);
       
   622     }
       
   623 
       
   624     public static void compareLines(List<String> list1, List<String> list2)
       
   625             throws ResourcesNotEqualException {
       
   626         compareLines(list1, list2, false);
       
   627     }
       
   628 
       
   629     public static void compareLines(List<String> list1,
       
   630             List<String> list2, boolean trim) throws ResourcesNotEqualException {
       
   631         if ((list1 == list2) || (list1 == null && list2 == null)) return;
       
   632         if (list1.size() != list2.size())
       
   633             throw new ResourcesNotEqualException();
       
   634         int i = 0;
       
   635         int j = 0;
       
   636         while (i < list1.size() &&
       
   637                j < list2.size() &&
       
   638                equals(list1.get(i), list2.get(j), trim)) {
       
   639             i++; j++;
       
   640         }
       
   641         if (!(i == list1.size() && j == list2.size()))
       
   642             throw new ResourcesNotEqualException();
       
   643     }
       
   644 
       
   645     private static boolean equals(String s1, String s2, boolean trim) {
       
   646         return (trim ? s1.trim().equals(s2.trim()) : s1.equals(s2));
       
   647     }
       
   648 
       
   649     /**
       
   650      * A set of simple grep-like methods, looks for regExpr in text.
       
   651      * The content of text is split using the new line character as a pattern
       
   652      * and later the regExpr is seek in every split line. If a match is found,
       
   653      * the whole line is added to the result.
       
   654      */
       
   655     public static List<String> grep(String regExpr, String text) {
       
   656         return grep(regExpr, splitLines(text));
       
   657     }
       
   658 
       
   659     public static List<String> grep(String regExpr, List<String> text) {
       
   660         List<String> result = new ArrayList<>();
       
   661         Pattern pattern = Pattern.compile(regExpr);
       
   662         for (String s : text) {
       
   663             if (pattern.matcher(s).find()) {
       
   664                 result.add(s);
       
   665             }
       
   666         }
       
   667         return result;
       
   668     }
       
   669 
       
   670     public static List<String> grep(String regExpr, File f)
       
   671             throws IOException {
       
   672         List<String> lines = Files.readAllLines(f.toPath(), defaultCharset);
       
   673         return grep(regExpr, lines);
       
   674     }
       
   675 
       
   676     /**
       
   677      * A touch-like method.
       
   678      */
       
   679     public static boolean touch(String fileName) {
       
   680         File file = new File(fileName);
       
   681         return touch(file);
       
   682     }
       
   683 
       
   684     public static boolean touch(File file) {
       
   685         if (file.exists()) {
       
   686             file.setLastModified(System.currentTimeMillis());
       
   687             return true;
       
   688         }
       
   689         return false;
       
   690     }
       
   691 
       
   692     public static void createJavaFile(File outFile) throws IOException {
       
   693         createJavaFile(outFile, null);
       
   694     }
       
   695 
       
   696     /**
       
   697      * A method for creating a valid but very simple java file.
       
   698      */
       
   699     public static void createJavaFile(File outFile, File superClass)
       
   700             throws IOException {
       
   701         String srcStr = "public class " + getSimpleName(outFile) + " ";
       
   702         if (superClass != null) {
       
   703             srcStr = srcStr.concat("extends " + getSimpleName(superClass) + " ");
       
   704         }
       
   705         srcStr = srcStr.concat("{}");
       
   706         try (PrintWriter ps = new PrintWriter(new FileWriter(outFile))) {
       
   707             ps.println(srcStr);
       
   708         }
       
   709     }
       
   710 
       
   711     /**
       
   712      * Creates a java file name given its source.
       
   713      * The file is created in the working directory, creating a directory
       
   714      * tree if there is a package declaration.
       
   715      */
       
   716     public static void createJavaFileFromSource(String source) throws IOException {
       
   717         createJavaFileFromSource(null, source);
       
   718     }
       
   719 
       
   720     /**
       
   721      * Creates a java file name given its source.
       
   722      * The file is created in the working directory, creating a directory
       
   723      * tree if there is a package declaration or the argument initialPath
       
   724      * has a valid path.
       
   725      *
       
   726      * e.i. if initialPath is foo/ and the source is:
       
   727      * package bar;
       
   728      *
       
   729      * public class bazz {}
       
   730      *
       
   731      * this method will create the file foo/bar/bazz.java in the working
       
   732      * directory.
       
   733      */
       
   734     public static void createJavaFileFromSource(Path initialPath,
       
   735             String source) throws IOException {
       
   736         String fileName = getJavaFileNameFromSource(source);
       
   737         String dirTree = getDirTreeFromSource(source);
       
   738         Path path = (dirTree != null) ?
       
   739                 Paths.get(dirTree, fileName) :
       
   740                 Paths.get(fileName);
       
   741         path = (initialPath != null) ?
       
   742                 initialPath.resolve(path):
       
   743                 path;
       
   744         writeFile(path, source);
       
   745     }
       
   746 
       
   747     static Pattern publicClassPattern =
       
   748             Pattern.compile("public\\s+(?:class|enum|interface){1}\\s+(\\w+)");
       
   749     static Pattern packageClassPattern =
       
   750             Pattern.compile("(?:class|enum|interface){1}\\s+(\\w+)");
       
   751 
       
   752     /**
       
   753      * Extracts the java file name from the class declaration.
       
   754      * This method is intended for simple files and uses regular expressions,
       
   755      * so comments matching the pattern can make the method fail.
       
   756      */
       
   757     private static String getJavaFileNameFromSource(String source) {
       
   758         String className = null;
       
   759         Matcher matcher = publicClassPattern.matcher(source);
       
   760         if (matcher.find()) {
       
   761             className = matcher.group(1) + ".java";
       
   762         } else {
       
   763             matcher = packageClassPattern.matcher(source);
       
   764             if (matcher.find()) {
       
   765                 className = matcher.group(1) + ".java";
       
   766             } else {
       
   767                 throw new AssertionError("Could not extract the java class " +
       
   768                         "name from the provided source");
       
   769             }
       
   770         }
       
   771         return className;
       
   772     }
       
   773 
       
   774     static Pattern packagePattern =
       
   775             Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))");
       
   776 
       
   777     /**
       
   778      * Extracts the path from the package declaration if present.
       
   779      * This method is intended for simple files and uses regular expressions,
       
   780      * so comments matching the pattern can make the method fail.
       
   781      */
       
   782     private static String getDirTreeFromSource(String source) {
       
   783         Matcher matcher = packagePattern.matcher(source);
       
   784         return matcher.find() ?
       
   785             matcher.group(1).replace(".", File.separator) :
       
   786             null;
       
   787     }
       
   788 
       
   789     /**
       
   790      * A method for creating a jar's manifest file with supplied data.
       
   791      */
       
   792     public static void mkManifestWithClassPath(String mainClass,
       
   793             String... classes) throws IOException {
       
   794         List <String> lines = new ArrayList<>();
       
   795 
       
   796         StringBuilder sb = new StringBuilder("Class-Path: ".length() +
       
   797                 classes[0].length()).append("Class-Path: ").append(classes[0]);
       
   798         for (int i = 1; i < classes.length; i++) {
       
   799             sb.append(" ").append(classes[i]);
       
   800         }
       
   801         lines.add(sb.toString());
       
   802         if (mainClass != null) {
       
   803             lines.add(new StringBuilder("Main-Class: ".length() +
       
   804                       mainClass.length())
       
   805                       .append("Main-Class: ")
       
   806                       .append(mainClass).toString());
       
   807         }
       
   808         Files.write(Paths.get("MANIFEST.MF"), lines, null);
       
   809     }
       
   810 
       
   811     /**
       
   812      * A utility method to obtain the file name.
       
   813      */
       
   814     static String getSimpleName(File inFile) {
       
   815         return inFile.toPath().getFileName().toString();
       
   816     }
       
   817 
       
   818     /**
       
   819      * A method to write to a file, the directory tree is created if needed.
       
   820      */
       
   821     public static File writeFile(Path path, String body) throws IOException {
       
   822         File result;
       
   823         if (path.getParent() != null) {
       
   824             Files.createDirectories(path.getParent());
       
   825         }
       
   826         try (FileWriter out = new FileWriter(result = path.toAbsolutePath().toFile())) {
       
   827             out.write(body);
       
   828         }
       
   829         return result;
       
   830     }
       
   831 
       
   832     public static File writeFile(String path, String body) throws IOException {
       
   833         return writeFile(Paths.get(path), body);
       
   834     }
       
   835 
       
   836     /**
       
   837      * A rm-like method, the file is deleted only if it exists.
       
   838      */
       
   839     public static void rm(Path path) throws Exception {
       
   840         Files.deleteIfExists(path);
       
   841     }
       
   842 
       
   843     public static void rm(String filename) throws Exception {
       
   844         rm(Paths.get(filename));
       
   845     }
       
   846 
       
   847     public static void rm(File f) throws Exception {
       
   848         rm(f.toPath());
       
   849     }
       
   850 
       
   851     /**
       
   852      * Copy source file to destination file.
       
   853      */
       
   854     public static void copyFile(File destfile, File srcfile)
       
   855         throws IOException {
       
   856         copyFile(destfile.toPath(), srcfile.toPath());
       
   857     }
       
   858 
       
   859     public static void copyFile(Path destPath, Path srcPath)
       
   860         throws IOException {
       
   861         Files.createDirectories(destPath);
       
   862         Files.copy(srcPath, destPath, REPLACE_EXISTING);
       
   863     }
       
   864 
       
   865     /**
       
   866      * Splits a String using the System's line separator character as splitting point.
       
   867      */
       
   868     public static List<String> splitLines(String lines) {
       
   869         return Arrays.asList(lines.split(lineSeparator));
       
   870     }
       
   871 
       
   872     /**
       
   873      * Converts a String list into one String by appending the System's line separator
       
   874      * character after each component.
       
   875      */
       
   876     private static String listToString(List<String> lines) {
       
   877         StringBuilder sb = new StringBuilder();
       
   878         for (String s : lines) {
       
   879             sb.append(s).append(lineSeparator);
       
   880         }
       
   881         return sb.toString();
       
   882     }
       
   883 
       
   884     /**
       
   885      * Class representing an in-memory java source file. It is able to extract
       
   886      * the file name from simple source codes using regular expressions.
       
   887      */
       
   888     public static class JavaSource extends SimpleJavaFileObject {
       
   889         String source;
       
   890         String name;
       
   891 
       
   892         public JavaSource(String className, String source) {
       
   893             super(URI.create(className),
       
   894                     JavaFileObject.Kind.SOURCE);
       
   895             this.name = className;
       
   896             this.source = source;
       
   897         }
       
   898 
       
   899         public JavaSource(String source) {
       
   900             super(URI.create(getJavaFileNameFromSource(source)),
       
   901                     JavaFileObject.Kind.SOURCE);
       
   902             this.name = getJavaFileNameFromSource(source);
       
   903             this.source = source;
       
   904         }
       
   905 
       
   906         @Override
       
   907         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       
   908             return source;
       
   909         }
       
   910     }
       
   911 }