de.plugins.eclipse.depclipse.testcommons.Util.java Source code

Java tutorial

Introduction

Here is the source code for de.plugins.eclipse.depclipse.testcommons.Util.java

Source

package de.plugins.eclipse.depclipse.testcommons;
/*******************************************************************************
 * Copyright (c) 2000, 2009 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Nina Rinskaya
 *           Fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=172820.
 *******************************************************************************/

import java.io.*;
import java.net.ServerSocket;
import java.util.*;
import java.util.zip.*;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;

@SuppressWarnings("restriction")
public class Util {
    // Trace for delete operation
    /*
     * Maximum time wasted repeating delete operations while running JDT/Core tests.
     */
    private static int DELETE_MAX_TIME = 0;
    /**
     * Trace deletion operations while running JDT/Core tests.
     */
    public static boolean DELETE_DEBUG = false;
    /**
     * Maximum of time in ms to wait in deletion operation while running JDT/Core tests.
     * Default is 10 seconds. This number cannot exceed 1 minute (ie. 60000).
     * <br>
     * To avoid too many loops while waiting, the ten first ones are done waiting
     * 10ms before repeating, the ten loops after are done waiting 100ms and
     * the other loops are done waiting 1s...
     */
    public static int DELETE_MAX_WAIT = 10000;

    private static final boolean DEBUG = false;
    /**
     * Initially, output directory was located in System.getProperty("user.home")+"\comptest".
     * To allow user to run several compiler tests at the same time, main output directory
     * is now located in a sub-directory of "comptest" which name is "run."+<code>System.currentMilliseconds</code>.
     *
     * @see #DELAY_BEFORE_CLEAN_PREVIOUS
     */
    private final static String OUTPUT_DIRECTORY;
    /**
     * Let user specify the delay in hours before output directories are removed from file system
     * while starting a new test run. Default value is 2 hours.
     * <p>
     * Note that this value may be a float and so have time less than one hour.
     * If value is 0 or negative, then all previous run directories will be removed...
     *
     * @see #OUTPUT_DIRECTORY
     */
    private final static String DELAY_BEFORE_CLEAN_PREVIOUS = System.getProperty("delay");
    /*
     * Static initializer to clean directories created while running previous test suites.
     */
    static {
        // Get delay for cleaning sub-directories
        long millisecondsPerHour = 1000L * 3600L;
        long delay = millisecondsPerHour * 2; // default is to keep previous run directories for 2 hours
        try {
            if (DELAY_BEFORE_CLEAN_PREVIOUS != null) {
                float hours = Float.parseFloat(DELAY_BEFORE_CLEAN_PREVIOUS);
                delay = (int) (millisecondsPerHour * hours);
            }
        } catch (NumberFormatException nfe) {
            // use default
        }

        // Get output directory root from system properties
        String container = System.getProperty("jdt.test.output_directory");
        if (container == null) {
            container = System.getProperty("user.home");
        }
        if (container == null) {
            container = "."; // use current directory
        }

        // Get file for root directory
        if (Character.isLowerCase(container.charAt(0)) && container.charAt(1) == ':') {
            container = Character.toUpperCase(container.charAt(0)) + container.substring(1);
        }
        File dir = new File(new File(container), "comptest");

        // If root directory already exists, clean it
        if (dir.exists()) {
            long now = System.currentTimeMillis();
            if ((now - dir.lastModified()) > delay) {
                // remove all directory content
                flushDirectoryContent(dir);
            } else {
                // remove only old sub-dirs
                File[] testDirs = dir.listFiles();
                for (int i = 0, l = testDirs.length; i < l; i++) {
                    if (testDirs[i].isDirectory()) {
                        if ((now - testDirs[i].lastModified()) > delay) {
                            delete(testDirs[i]);
                        }
                    }
                }
            }
        }

        // Computed test run directory name based on current time
        File dateDir = new File(dir, "run." + System.currentTimeMillis());
        OUTPUT_DIRECTORY = dateDir.getPath();
    }

    public static void appendProblem(StringBuffer problems, IProblem problem, char[] source, int problemCount) {
        problems.append(problemCount + (problem.isError() ? ". ERROR" : ". WARNING"));
        problems.append(" in " + new String(problem.getOriginatingFileName()));
        if (source != null) {
            problems.append(((DefaultProblem) problem).errorReportSource(source));
        }
        problems.append("\n");
        problems.append(problem.getMessage());
        problems.append("\n");
    }

    public static CompilationUnit[] compilationUnits(String[] testFiles) {
        int length = testFiles.length / 2;
        CompilationUnit[] result = new CompilationUnit[length];
        int index = 0;
        for (int i = 0; i < length; i++) {
            result[i] = new CompilationUnit(testFiles[index + 1].toCharArray(), testFiles[index], null);
            index += 2;
        }
        return result;
    }

    public static String[] concatWithClassLibs(String[] classpaths, boolean inFront) {
        String[] classLibs = getJavaClassLibs();
        if (classpaths == null)
            return classLibs;
        final int classLibsLength = classLibs.length;
        final int classpathsLength = classpaths.length;
        String[] defaultClassPaths = new String[classLibsLength + classpathsLength];
        if (inFront) {
            System.arraycopy(classLibs, 0, defaultClassPaths, classpathsLength, classLibsLength);
            System.arraycopy(classpaths, 0, defaultClassPaths, 0, classpathsLength);
        } else {
            System.arraycopy(classLibs, 0, defaultClassPaths, 0, classLibsLength);
            System.arraycopy(classpaths, 0, defaultClassPaths, classLibsLength, classpathsLength);
        }
        for (int i = 0; i < classpathsLength; i++) {
            File file = new File(classpaths[i]);
            if (!file.exists()) {
                file.mkdirs();
            }
        }
        return defaultClassPaths;
    }

    public static String[] concatWithClassLibs(String classpath, boolean inFront) {
        String[] classLibs = getJavaClassLibs();
        final int length = classLibs.length;
        File dir = new File(classpath);
        if (!dir.exists())
            dir.mkdirs();
        String[] defaultClassPaths = new String[length + 1];
        if (inFront) {
            System.arraycopy(classLibs, 0, defaultClassPaths, 1, length);
            defaultClassPaths[0] = classpath;
        } else {
            System.arraycopy(classLibs, 0, defaultClassPaths, 0, length);
            defaultClassPaths[length] = classpath;
        }
        return defaultClassPaths;
    }

    public static String convertToIndependantLineDelimiter(String source) {
        if (source == null)
            return "";
        if (source.indexOf('\n') == -1 && source.indexOf('\r') == -1)
            return source;
        StringBuffer buffer = new StringBuffer();
        for (int i = 0, length = source.length(); i < length; i++) {
            char car = source.charAt(i);
            if (car == '\r') {
                buffer.append('\n');
                if (i < length - 1 && source.charAt(i + 1) == '\n') {
                    i++; // skip \n after \r
                }
            } else {
                buffer.append(car);
            }
        }
        return buffer.toString();
    }

    /**
     * Copy the given source (a file or a directory that must exists) to the given destination (a directory that must exists).
     */
    public static void copy(String sourcePath, String destPath) {
        sourcePath = toNativePath(sourcePath);
        destPath = toNativePath(destPath);
        File source = new File(sourcePath);
        if (!source.exists())
            return;
        File dest = new File(destPath);
        if (!dest.exists())
            return;
        if (source.isDirectory()) {
            String[] files = source.list();
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    String file = files[i];
                    File sourceFile = new File(source, file);
                    if (sourceFile.isDirectory()) {
                        File destSubDir = new File(dest, file);
                        destSubDir.mkdir();
                        copy(sourceFile.getPath(), destSubDir.getPath());
                    } else {
                        copy(sourceFile.getPath(), dest.getPath());
                    }
                }
            }
        } else {
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream(source);
                File destFile = new File(dest, source.getName());
                if (destFile.exists()) {
                    if (!Util.delete(destFile)) {
                        throw new IOException(destFile + " is in use");
                    }
                }
                out = new FileOutputStream(destFile);
                int bufferLength = 1024;
                byte[] buffer = new byte[bufferLength];
                int read = 0;
                while (read != -1) {
                    read = in.read(buffer, 0, bufferLength);
                    if (read != -1) {
                        out.write(buffer, 0, read);
                    }
                }
            } catch (IOException e) {
                throw new Error(e.toString());
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
    }

    public static void createFile(String path, String contents) throws IOException {
        FileOutputStream output = new FileOutputStream(path);
        try {
            output.write(contents.getBytes());
        } finally {
            output.close();
        }
    }

    public static void createSourceZip(String[] pathsAndContents, String zipPath) throws IOException {
        String sourcesPath = getOutputDirectory() + File.separator + "sources";
        createSourceDir(pathsAndContents, sourcesPath);
        zip(new File(sourcesPath), zipPath);
    }

    public static void createSourceDir(String[] pathsAndContents, String sourcesPath) throws IOException {
        flushDirectoryContent(new File(sourcesPath));
        for (int i = 0, length = pathsAndContents.length; i < length; i += 2) {
            String sourcePath = sourcesPath + File.separator + pathsAndContents[i];
            File sourceFile = new File(sourcePath);
            sourceFile.getParentFile().mkdirs();
            createFile(sourcePath, pathsAndContents[i + 1]);
        }
    }

    /**
     * Delete a file or directory and insure that the file is no longer present
     * on file system. In case of directory, delete all the hierarchy underneath.
     *
     * @param file The file or directory to delete
     * @return true iff the file was really delete, false otherwise
     */
    public static boolean delete(File file) {
        // flush all directory content
        if (file.isDirectory()) {
            flushDirectoryContent(file);
        }
        // remove file
        file.delete();
        if (isFileDeleted(file)) {
            return true;
        }
        return waitUntilFileDeleted(file);
    }

    /**
     * Delete a file or directory and insure that the file is no longer present
     * on file system. In case of directory, delete all the hierarchy underneath.
     *
     * @param resource The resource to delete
     * @return true iff the file was really delete, false otherwise
     */
    public static boolean delete(IResource resource) {
        try {
            resource.delete(true, null);
            if (isResourceDeleted(resource)) {
                return true;
            }
        } catch (CoreException e) {
            //   skip
        }
        return waitUntilResourceDeleted(resource);
    }

    /**
     * Delete a file or directory and insure that the file is no longer present
     * on file system. In case of directory, delete all the hierarchy underneath.
     *
     * @param path The path of the file or directory to delete
     * @return true iff the file was really delete, false otherwise
     */
    public static boolean delete(String path) {
        return delete(new File(path));
    }

    /**
     * Generate a display string from the given String.
     * @param inputString the given input string
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.displayString("abc\ndef\tghi")]
    */
    public static String displayString(String inputString) {
        return displayString(inputString, 0);
    }

    /**
     * Generate a display string from the given String.
     * It converts:
     * <ul>
     * <li>\t to \t</li>
     * <li>\r to \\r</li>
     * <li>\n to \n</li>
     * <li>\b to \\b</li>
     * <li>\f to \\f</li>
     * <li>\" to \\\"</li>
     * <li>\' to \\'</li>
     * <li>\\ to \\\\</li>
     * <li>All other characters are unchanged.</li>
     * </ul>
     * This method doesn't convert \r\n to \n.
     * <p>
     * Example of use:
     * <o>
     * <li>
     * <pre>
     * input string = "abc\ndef\tghi",
     * indent = 3
     * result = "\"\t\t\tabc\\n" +
     *          "\t\t\tdef\tghi\""
     * </pre>
     * </li>
     * <li>
     * <pre>
     * input string = "abc\ndef\tghi\n",
     * indent = 3
     * result = "\"\t\t\tabc\\n" +
     *          "\t\t\tdef\tghi\\n\""
     * </pre>
     * </li>
     * <li>
     * <pre>
     * input string = "abc\r\ndef\tghi\r\n",
     * indent = 3
     * result = "\"\t\t\tabc\\r\\n" +
     *          "\t\t\tdef\tghi\\r\\n\""
     * </pre>
     * </li>
     * </ol>
     * </p>
     *
     * @param inputString the given input string
     * @param indent number of tabs are added at the begining of each line.
     *
     * @return the displayed string
    */
    public static String displayString(String inputString, int indent) {
        return displayString(inputString, indent, false);
    }

    public static String displayString(String inputString, int indent, boolean shift) {
        if (inputString == null)
            return "null";
        int length = inputString.length();
        StringBuffer buffer = new StringBuffer(length);
        java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(inputString, "\n\r", true);
        for (int i = 0; i < indent; i++)
            buffer.append("\t");
        if (shift)
            indent++;
        buffer.append("\"");
        while (tokenizer.hasMoreTokens()) {

            String token = tokenizer.nextToken();
            if (token.equals("\r")) {
                buffer.append("\\r");
                if (tokenizer.hasMoreTokens()) {
                    token = tokenizer.nextToken();
                    if (token.equals("\n")) {
                        buffer.append("\\n");
                        if (tokenizer.hasMoreTokens()) {
                            buffer.append("\" + \n");
                            for (int i = 0; i < indent; i++)
                                buffer.append("\t");
                            buffer.append("\"");
                        }
                        continue;
                    }
                    buffer.append("\" + \n");
                    for (int i = 0; i < indent; i++)
                        buffer.append("\t");
                    buffer.append("\"");
                } else {
                    continue;
                }
            } else if (token.equals("\n")) {
                buffer.append("\\n");
                if (tokenizer.hasMoreTokens()) {
                    buffer.append("\" + \n");
                    for (int i = 0; i < indent; i++)
                        buffer.append("\t");
                    buffer.append("\"");
                }
                continue;
            }

            StringBuffer tokenBuffer = new StringBuffer();
            for (int i = 0; i < token.length(); i++) {
                char c = token.charAt(i);
                switch (c) {
                case '\r':
                    tokenBuffer.append("\\r");
                    break;
                case '\n':
                    tokenBuffer.append("\\n");
                    break;
                case '\b':
                    tokenBuffer.append("\\b");
                    break;
                case '\t':
                    tokenBuffer.append("\t");
                    break;
                case '\f':
                    tokenBuffer.append("\\f");
                    break;
                case '\"':
                    tokenBuffer.append("\\\"");
                    break;
                case '\'':
                    tokenBuffer.append("\\'");
                    break;
                case '\\':
                    tokenBuffer.append("\\\\");
                    break;
                default:
                    tokenBuffer.append(c);
                }
            }
            buffer.append(tokenBuffer.toString());
        }
        buffer.append("\"");
        return buffer.toString();
    }

    /**
     * Reads the content of the given source file.
     * Returns null if enable to read given source file.
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.fileContent("c:/temp/X.java")]
    */
    public static String fileContent(String sourceFilePath) {
        File sourceFile = new File(sourceFilePath);
        if (!sourceFile.exists()) {
            if (DEBUG)
                System.out.println("File " + sourceFilePath + " does not exists.");
            return null;
        }
        if (!sourceFile.isFile()) {
            if (DEBUG)
                System.out.println(sourceFilePath + " is not a file.");
            return null;
        }
        StringBuffer sourceContentBuffer = new StringBuffer();
        FileInputStream input = null;
        try {
            input = new FileInputStream(sourceFile);
        } catch (FileNotFoundException e) {
            return null;
        }
        try {
            int read;
            do {
                read = input.read();
                if (read != -1) {
                    sourceContentBuffer.append((char) read);
                }
            } while (read != -1);
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                input.close();
            } catch (IOException e2) {
            }
        }
        return sourceContentBuffer.toString();
    }

    /**
     * Reads the content of the given source file and converts it to a display string.
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("c:/temp/X.java", 0)]
    */
    public static String fileContentToDisplayString(String sourceFilePath, int indent,
            boolean independantLineDelimiter) {
        String sourceString = fileContent(sourceFilePath);
        if (independantLineDelimiter) {
            sourceString = convertToIndependantLineDelimiter(sourceString);
        }
        return displayString(sourceString, indent);
    }

    /**
     * Reads the content of the given source file, converts it to a display string.
     * If the destination file path is not null, writes the result to this file.
     * Otherwise writes it to the console.
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("c:/temp/X.java", 0, null)]
    */
    public static void fileContentToDisplayString(String sourceFilePath, int indent, String destinationFilePath,
            boolean independantLineDelimiter) {
        String displayString = fileContentToDisplayString(sourceFilePath, indent, independantLineDelimiter);
        if (destinationFilePath == null) {
            System.out.println(displayString);
            return;
        }
        writeToFile(displayString, destinationFilePath);
    }

    /**
     * Flush content of a given directory (leaving it empty),
     * no-op if not a directory.
     */
    public static void flushDirectoryContent(File dir) {
        File[] files = dir.listFiles();
        if (files == null)
            return;
        for (int i = 0, max = files.length; i < max; i++) {
            delete(files[i]);
        }
    }

    /**
     * Returns the next available port number on the local host.
     */
    public static int getFreePort() {
        ServerSocket socket = null;
        try {
            socket = new ServerSocket(0);
            return socket.getLocalPort();
        } catch (IOException e) {
            // ignore
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
        return -1;
    }

    /**
     * Search the user hard-drive for a Java class library.
     * Returns null if none could be found.
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.getJavaClassLib()]
    */
    public static String[] getJavaClassLibs() {
        // check bootclasspath properties for Sun, JRockit and Harmony VMs
        String bootclasspathProperty = System.getProperty("sun.boot.class.path"); //$NON-NLS-1$
        if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) {
            // IBM J9 VMs
            bootclasspathProperty = System.getProperty("vm.boot.class.path"); //$NON-NLS-1$
            if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) {
                // Harmony using IBM VME
                bootclasspathProperty = System.getProperty("org.apache.harmony.boot.class.path"); //$NON-NLS-1$
            }
        }
        String[] jars = null;
        if ((bootclasspathProperty != null) && (bootclasspathProperty.length() != 0)) {
            StringTokenizer tokenizer = new StringTokenizer(bootclasspathProperty, File.pathSeparator);
            final int size = tokenizer.countTokens();
            jars = new String[size];
            int i = 0;
            while (tokenizer.hasMoreTokens()) {
                final String fileName = toNativePath(tokenizer.nextToken());
                if (new File(fileName).exists()) {
                    jars[i] = fileName;
                    i++;
                }
            }
            if (size != i) {
                // resize
                System.arraycopy(jars, 0, (jars = new String[i]), 0, i);
            }
        } else {
            String jreDir = getJREDirectory();
            final String osName = System.getProperty("os.name");
            if (jreDir == null) {
                return new String[] {};
            }
            if (osName.startsWith("Mac")) {
                return new String[] { toNativePath(jreDir + "/../Classes/classes.jar") };
            }
            final String vmName = System.getProperty("java.vm.name");
            if ("J9".equals(vmName)) {
                return new String[] { toNativePath(jreDir + "/lib/jclMax/classes.zip") };
            }
            String[] jarsNames = null;
            ArrayList<String> paths = new ArrayList<String>();
            if ("DRLVM".equals(vmName)) {
                FilenameFilter jarFilter = new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                        return name.endsWith(".jar") & !name.endsWith("-src.jar");
                    }
                };
                jarsNames = new File(jreDir + "/lib/boot/").list(jarFilter);
                addJarEntries(jreDir + "/lib/boot/", jarsNames, paths);
            } else {
                jarsNames = new String[] { "/lib/vm.jar", "/lib/rt.jar", "/lib/core.jar", "/lib/security.jar",
                        "/lib/xml.jar", "/lib/graphics.jar" };
                addJarEntries(jreDir, jarsNames, paths);
            }
            jars = new String[paths.size()];
            paths.toArray(jars);
        }
        return jars;
    }

    private static void addJarEntries(String jreDir, String[] jarNames, ArrayList<String> paths) {
        for (int i = 0, max = jarNames.length; i < max; i++) {
            final String currentName = jreDir + jarNames[i];
            File f = new File(currentName);
            if (f.exists()) {
                paths.add(toNativePath(currentName));
            }
        }
    }

    public static String getJavaClassLibsAsString() {
        String[] classLibs = getJavaClassLibs();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0, max = classLibs.length; i < max; i++) {
            buffer.append(classLibs[i]).append(File.pathSeparatorChar);
        }
        return buffer.toString();
    }

    /**
     * Returns the JRE directory this tests are running on.
     * Returns null if none could be found.
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.getJREDirectory()]
     */
    public static String getJREDirectory() {
        return System.getProperty("java.home");
    }

    /**
     * Search the user hard-drive for a possible output directory.
     * Returns null if none could be found.
     *
     * Example of use: [org.eclipse.jdt.core.tests.util.Util.getOutputDirectory()]
     */
    public static String getOutputDirectory() {
        return OUTPUT_DIRECTORY;
    }

    /**
     * Returns the parent's child file matching the given file or null if not found.
     *
     * @param file The searched file in parent
     * @return The parent's child matching the given file or null if not found.
     */
    private static File getParentChildFile(File file) {
        File parent = file.getParentFile();
        if (parent == null || !parent.exists())
            return null;
        File[] files = parent.listFiles();
        int length = files == null ? 0 : files.length;
        if (length > 0) {
            for (int i = 0; i < length; i++) {
                if (files[i] == file) {
                    return files[i];
                } else if (files[i].equals(file)) {
                    return files[i];
                } else if (files[i].getPath().equals(file.getPath())) {
                    return files[i];
                }
            }
        }
        return null;
    }

    /**
     * Returns parent's child resource matching the given resource or null if not found.
     *
     * @param resource The searched file in parent
     * @return The parent's child matching the given file or null if not found.
     */
    private static IResource getParentChildResource(IResource resource) {
        IContainer parent = resource.getParent();
        if (parent == null || !parent.exists())
            return null;
        try {
            IResource[] members = parent.members();
            int length = members == null ? 0 : members.length;
            if (length > 0) {
                for (int i = 0; i < length; i++) {
                    if (members[i] == resource) {
                        return members[i];
                    } else if (members[i].equals(resource)) {
                        return members[i];
                    } else if (members[i].getFullPath().equals(resource.getFullPath())) {
                        return members[i];
                    }
                }
            }
        } catch (CoreException ce) {
            // skip
        }
        return null;
    }

    /**
     * Returns the test name from stack elements info.
     *
     * @return The name of the test currently running
     */
    private static String getTestName() {
        StackTraceElement[] elements = new Exception().getStackTrace();
        int idx = 0, length = elements.length;
        while (idx < length && !elements[idx++].getClassName().startsWith("org.eclipse.jdt")) {
            // loop until JDT/Core class appears in the stack
        }
        if (idx < length) {
            StackTraceElement testElement = null;
            while (idx < length && elements[idx].getClassName().startsWith("org.eclipse.jdt")) {
                testElement = elements[idx++];
            }
            if (testElement != null) {
                return testElement.getClassName() + " - " + testElement.getMethodName();
            }
        }
        return "?";
    }

    public static String indentString(String inputString, int indent) {
        if (inputString == null)
            return "";
        int length = inputString.length();
        StringBuffer buffer = new StringBuffer(length);
        java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(inputString, "\n\r", true);
        StringBuffer indentStr = new StringBuffer(indent);
        for (int i = 0; i < indent; i++)
            indentStr.append("\t");
        buffer.append(indentStr);
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            buffer.append(token);
            if (token.equals("\r") || token.equals("\n")) {
                buffer.append(indentStr);
            }
        }
        return buffer.toString();
    }

    /**
     * Returns whether a file is really deleted or not.
     * Does not only rely on {@link File#exists()} method but also
     * look if it's not in its parent children {@link #getParentChildFile(File)}.
     *
     * @param file The file to test if deleted
     * @return true if the file does not exist and was not found in its parent children.
     */
    public static boolean isFileDeleted(File file) {
        return !file.exists() && getParentChildFile(file) == null;
    }

    public static boolean isMacOS() {
        return System.getProperty("os.name").indexOf("Mac") != -1;
    }

    /**
     * Returns whether a resource is really deleted or not.
     * Does not only rely on {@link IResource#isAccessible()} method but also
     * look if it's not in its parent children {@link #getParentChildResource(IResource)}.
     *
     * @param resource The resource to test if deleted
     * @return true if the resource is not accessible and was not found in its parent children.
     */
    public static boolean isResourceDeleted(IResource resource) {
        return !resource.isAccessible() && getParentChildResource(resource) == null;
    }

    /**
     * Print given file information with specified indentation.
     * These information are:<ul>
     *    <li>read {@link File#canRead()}</li>
     *    <li>write {@link File#canWrite()}</li>
     *    <li>exists {@link File#exists()}</li>
     *    <li>is file {@link File#isFile()}</li>
     *    <li>is directory {@link File#isDirectory()}</li>
     *    <li>is hidden {@link File#isHidden()}</li>
     * </ul>
     * May recurse several level in parents hierarchy.
     * May also display children, but then will not recusre in parent
     * hierarchy to avoid infinite loop...
     *
     * @param file The file to display information
     * @param indent Number of tab to print before the information
     * @param recurse Display also information on <code>recurse</code>th parents in hierarchy.
     *    If negative then display children information instead.
     */
    private static void printFileInfo(File file, int indent, int recurse) {
        String tab = "";
        for (int i = 0; i < indent; i++)
            tab += "\t";
        System.out.print(tab + "- " + file.getName() + " file info: ");
        String sep = "";
        if (file.canRead()) {
            System.out.print("read");
            sep = ", ";
        }
        if (file.canWrite()) {
            System.out.print(sep + "write");
            sep = ", ";
        }
        if (file.exists()) {
            System.out.print(sep + "exist");
            sep = ", ";
        }
        if (file.isDirectory()) {
            System.out.print(sep + "dir");
            sep = ", ";
        }
        if (file.isFile()) {
            System.out.print(sep + "file");
            sep = ", ";
        }
        if (file.isHidden()) {
            System.out.print(sep + "hidden");
            sep = ", ";
        }
        System.out.println();
        File[] files = file.listFiles();
        int length = files == null ? 0 : files.length;
        if (length > 0) {
            boolean children = recurse < 0;
            System.out.print(tab + "   + children: ");
            if (children)
                System.out.println();
            for (int i = 0; i < length; i++) {
                if (children) { // display children
                    printFileInfo(files[i], indent + 2, -1);
                } else {
                    if (i > 0)
                        System.out.print(", ");
                    System.out.print(files[i].getName());
                    if (files[i].isDirectory())
                        System.out.print("[dir]");
                    else if (files[i].isFile())
                        System.out.print("[file]");
                    else
                        System.out.print("[?]");
                }
            }
            if (!children)
                System.out.println();
        }
        if (recurse > 0) {
            File parent = file.getParentFile();
            if (parent != null)
                printFileInfo(parent, indent + 1, recurse - 1);
        }
    }

    /**
     * Print stack trace with only JDT/Core elements.
     *
     * @param exception Exception of the stack trace. May be null, then a fake exception is used.
     * @param indent Number of tab to display before the stack elements to display.
     */
    private static void printJdtCoreStackTrace(Exception exception, int indent) {
        String tab = "";
        for (int i = 0; i < indent; i++)
            tab += "\t";
        StackTraceElement[] elements = (exception == null ? new Exception() : exception).getStackTrace();
        int idx = 0, length = elements.length;
        while (idx < length && !elements[idx++].getClassName().startsWith("org.eclipse.jdt")) {
            // loop until JDT/Core class appears in the stack
        }
        if (idx < length) {
            System.out.print(tab + "- stack trace");
            if (exception == null)
                System.out.println(":");
            else
                System.out.println(" for exception " + exception + ":");
            while (idx < length && elements[idx].getClassName().startsWith("org.eclipse.jdt")) {
                StackTraceElement testElement = elements[idx++];
                System.out.println(tab + "   -> " + testElement);
            }
        } else {
            exception.printStackTrace(System.out);
        }
    }

    /**
     * Makes the given path a path using native path separators as returned by File.getPath()
     * and trimming any extra slash.
     */
    public static String toNativePath(String path) {
        String nativePath = path.replace('\\', File.separatorChar).replace('/', File.separatorChar);
        return nativePath.endsWith("/") || nativePath.endsWith("\\")
                ? nativePath.substring(0, nativePath.length() - 1)
                : nativePath;
    }

    public static String toString(String[] strings, boolean addExtraNewLine) {
        if (strings == null)
            return "null";
        StringBuffer buffer = new StringBuffer();
        for (int i = 0, length = strings.length; i < length; i++) {
            buffer.append(strings[i]);
            if (addExtraNewLine || i < length - 1)
                buffer.append("\n");
        }
        return buffer.toString();
    }

    /**
     * Unzip the contents of the given zip in the given directory (create it if it doesn't exist)
     */
    public static void unzip(String zipPath, String destDirPath) throws IOException {

        InputStream zipIn = new FileInputStream(zipPath);
        byte[] buf = new byte[8192];
        File destDir = new File(destDirPath);
        ZipInputStream zis = new ZipInputStream(zipIn);
        FileOutputStream fos = null;
        try {
            ZipEntry zEntry;
            while ((zEntry = zis.getNextEntry()) != null) {
                // if it is empty directory, create it
                if (zEntry.isDirectory()) {
                    new File(destDir, zEntry.getName()).mkdirs();
                    continue;
                }
                // if it is a file, extract it
                String filePath = zEntry.getName();
                int lastSeparator = filePath.lastIndexOf("/"); //$NON-NLS-1$
                String fileDir = ""; //$NON-NLS-1$
                if (lastSeparator >= 0) {
                    fileDir = filePath.substring(0, lastSeparator);
                }
                //create directory for a file
                new File(destDir, fileDir).mkdirs();
                //write file
                File outFile = new File(destDir, filePath);
                fos = new FileOutputStream(outFile);
                int n = 0;
                while ((n = zis.read(buf)) >= 0) {
                    fos.write(buf, 0, n);
                }
                fos.close();
            }
        } catch (IOException ioe) {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException ioe2) {
                }
            }
        } finally {
            try {
                zipIn.close();
                if (zis != null)
                    zis.close();
            } catch (IOException ioe) {
            }
        }
    }

    public static void waitAtLeast(int time) {
        long start = System.currentTimeMillis();
        do {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
            }
        } while ((System.currentTimeMillis() - start) < time);
    }

    /**
     * Wait until the file is _really_ deleted on file system.
     *
     * @param file Deleted file
     * @return true if the file was finally deleted, false otherwise
     */
    private static boolean waitUntilFileDeleted(File file) {
        if (DELETE_DEBUG) {
            System.out.println();
            System.out.println("WARNING in test: " + getTestName());
            System.out.println("   - problems occured while deleting " + file);
            printJdtCoreStackTrace(null, 1);
            printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
            System.out.print("   - wait for (" + DELETE_MAX_WAIT + "ms max): ");
        }
        int count = 0;
        int delay = 10; // ms
        int maxRetry = DELETE_MAX_WAIT / delay;
        int time = 0;
        while (count < maxRetry) {
            try {
                count++;
                Thread.sleep(delay);
                time += delay;
                if (time > DELETE_MAX_TIME)
                    DELETE_MAX_TIME = time;
                if (DELETE_DEBUG)
                    System.out.print('.');
                if (file.exists()) {
                    if (file.delete()) {
                        // SUCCESS
                        if (DELETE_DEBUG) {
                            System.out.println();
                            System.out.println("   => file really removed after " + time + "ms (max="
                                    + DELETE_MAX_TIME + "ms)");
                            System.out.println();
                        }
                        return true;
                    }
                }
                if (isFileDeleted(file)) {
                    // SUCCESS
                    if (DELETE_DEBUG) {
                        System.out.println();
                        System.out.println(
                                "   => file disappeared after " + time + "ms (max=" + DELETE_MAX_TIME + "ms)");
                        System.out.println();
                    }
                    return true;
                }
                // Increment waiting delay exponentially
                if (count >= 10 && delay <= 100) {
                    count = 1;
                    delay *= 10;
                    maxRetry = DELETE_MAX_WAIT / delay;
                    if ((DELETE_MAX_WAIT % delay) != 0) {
                        maxRetry++;
                    }
                }
            } catch (InterruptedException ie) {
                break; // end loop
            }
        }
        if (!DELETE_DEBUG) {
            System.out.println();
            System.out.println("WARNING in test: " + getTestName());
            System.out.println("   - problems occured while deleting " + file);
            printJdtCoreStackTrace(null, 1);
            printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
        }
        System.out.println();
        System.out.println("   !!! ERROR: " + file + " was never deleted even after having waited "
                + DELETE_MAX_TIME + "ms!!!");
        System.out.println();
        return false;
    }

    /**
     * Wait until a resource is _really_ deleted on file system.
     *
     * @param resource Deleted resource
     * @return true if the file was finally deleted, false otherwise
     */
    public static boolean waitUntilResourceDeleted(IResource resource) {
        IPath location = resource.getLocation();
        if (location == null) {
            System.out.println();
            System.out.println("   !!! ERROR: " + resource + " getLocation() returned null!!!");
            System.out.println();
            return false;
        }
        File file = location.toFile();
        if (DELETE_DEBUG) {
            System.out.println();
            System.out.println("WARNING in test: " + getTestName());
            System.out.println("   - problems occured while deleting resource " + resource);
            printJdtCoreStackTrace(null, 1);
            printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
            System.out.print("   - wait for (" + DELETE_MAX_WAIT + "ms max): ");
        }
        int count = 0;
        int delay = 10; // ms
        int maxRetry = DELETE_MAX_WAIT / delay;
        int time = 0;
        while (count < maxRetry) {
            try {
                count++;
                Thread.sleep(delay);
                time += delay;
                if (time > DELETE_MAX_TIME)
                    DELETE_MAX_TIME = time;
                if (DELETE_DEBUG)
                    System.out.print('.');
                if (resource.isAccessible()) {
                    try {
                        resource.delete(true, null);
                        if (isResourceDeleted(resource) && isFileDeleted(file)) {
                            // SUCCESS
                            if (DELETE_DEBUG) {
                                System.out.println();
                                System.out.println("   => resource really removed after " + time + "ms (max="
                                        + DELETE_MAX_TIME + "ms)");
                                System.out.println();
                            }
                            return true;
                        }
                    } catch (CoreException e) {
                        //   skip
                    }
                }
                if (isResourceDeleted(resource) && isFileDeleted(file)) {
                    // SUCCESS
                    if (DELETE_DEBUG) {
                        System.out.println();
                        System.out.println(
                                "   => resource disappeared after " + time + "ms (max=" + DELETE_MAX_TIME + "ms)");
                        System.out.println();
                    }
                    return true;
                }
                // Increment waiting delay exponentially
                if (count >= 10 && delay <= 100) {
                    count = 1;
                    delay *= 10;
                    maxRetry = DELETE_MAX_WAIT / delay;
                    if ((DELETE_MAX_WAIT % delay) != 0) {
                        maxRetry++;
                    }
                }
            } catch (InterruptedException ie) {
                break; // end loop
            }
        }
        if (!DELETE_DEBUG) {
            System.out.println();
            System.out.println("WARNING in test: " + getTestName());
            System.out.println("   - problems occured while deleting resource " + resource);
            printJdtCoreStackTrace(null, 1);
            printFileInfo(file.getParentFile(), 1, -1); // display parent with its children
        }
        System.out.println();
        System.out.println("   !!! ERROR: " + resource + " was never deleted even after having waited "
                + DELETE_MAX_TIME + "ms!!!");
        System.out.println();
        return false;
    }

    public static void writeToFile(String contents, String destinationFilePath) {
        File destFile = new File(destinationFilePath);
        FileOutputStream output = null;
        try {
            output = new FileOutputStream(destFile);
            PrintWriter writer = new PrintWriter(output);
            writer.print(contents);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e2) {
                }
            }
        }
    }

    public static void zip(File rootDir, String zipPath) throws IOException {
        ZipOutputStream zip = null;
        try {
            File zipFile = new File(zipPath);
            if (zipFile.exists()) {
                if (!delete(zipFile))
                    throw new IOException("Could not delete " + zipPath);
                // ensure the new zip file has a different timestamp than the previous one
                int timeToWait = 1000; // some platform (like Linux) have a 1s granularity)
                waitAtLeast(timeToWait);
            } else {
                zipFile.getParentFile().mkdirs();
            }
            zip = new ZipOutputStream(new FileOutputStream(zipFile));
            zip(rootDir, zip, rootDir.getPath().length() + 1); // 1 for last slash
        } finally {
            if (zip != null) {
                zip.close();
            }
        }
    }

    private static void zip(File dir, ZipOutputStream zip, int rootPathLength) throws IOException {
        File[] files = dir.listFiles();
        if (files != null) {
            for (int i = 0, length = files.length; i < length; i++) {
                File file = files[i];
                if (file.isFile()) {
                    String path = file.getPath();
                    path = path.substring(rootPathLength);
                    ZipEntry entry = new ZipEntry(path.replace('\\', '/'));
                    zip.putNextEntry(entry);
                    zip.write(org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file));
                    zip.closeEntry();
                } else {
                    zip(file, zip, rootPathLength);
                }
            }
        }
    }

    /**
     * Returns the compilation errors / warnings for the given CompilationResult.
     *
     * @param compilationResult the compilation result
     * @param showCategory
     * @param showWarningToken
     * @return String the problem log
     */
    public static String getProblemLog(CompilationResult compilationResult, boolean showCategory,
            boolean showWarningToken) {
        StringBuffer buffer = new StringBuffer(100);
        if (compilationResult.hasProblems() || compilationResult.hasTasks()) {
            CategorizedProblem[] problems = compilationResult.getAllProblems();
            int count = problems.length;
            int problemCount = 0;
            char[] unitSource = compilationResult.compilationUnit.getContents();
            for (int i = 0; i < count; i++) {
                DefaultProblem problem = (DefaultProblem) problems[i];
                if (problem != null) {
                    if (problemCount == 0)
                        buffer.append("----------\n");
                    problemCount++;
                    buffer.append(problemCount + (problem.isError() ? ". ERROR" : ". WARNING"));
                    buffer.append(" in " + new String(problem.getOriginatingFileName()).replace('/', '\\'));
                    try {
                        buffer.append(problem.errorReportSource(unitSource));
                        buffer.append("\n");
                        if (showCategory) {
                            String category = problem.getInternalCategoryMessage();
                            if (category != null) {
                                buffer.append("[@cat:").append(category).append("] ");
                            }
                        }
                        if (showWarningToken) {
                            int irritant = ProblemReporter.getIrritant(problem.getID());
                            if (irritant != 0) {
                                String warningToken = CompilerOptions.warningTokenFromIrritant(irritant);
                                if (warningToken != null) {
                                    buffer.append("[@sup:").append(warningToken).append("] ");
                                }
                            }
                        }
                        buffer.append(problem.getMessage());
                        buffer.append("\n");
                    } catch (Exception e) {
                    }
                    buffer.append("----------\n");
                }
            }
        }
        return buffer.toString();
    }

    public static long getMajorMinorVMVersion() {
        String classFileVersion = System.getProperty("java.class.version"); //$NON-NLS-1$
        if (classFileVersion != null) {
            String[] versionParts = classFileVersion.split("\\."); //$NON-NLS-1$
            if (versionParts.length >= 2) {
                int majorVersion = -1;
                try {
                    majorVersion = Integer.parseInt(versionParts[0]);
                } catch (NumberFormatException e) {
                    // ignore
                }
                int minorVersion = -1;
                try {
                    minorVersion = Integer.parseInt(versionParts[1]);
                } catch (NumberFormatException e) {
                    // ignore
                }
                if (minorVersion != -1 && majorVersion != -1) {
                    return ((long) majorVersion << 16) + minorVersion;
                }
            }
        }
        return -1;
    }
}