sandbox/java.hints/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java
branchdonation_review
changeset 1043 57843026e60b
parent 1027 205b7632914c
parent 1040 f7b6892fd754
child 1044 7feb751ba76b
     1.1 --- a/sandbox/java.hints/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java	Mon Dec 19 11:37:36 2016 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,1427 +0,0 @@
     1.4 -/*
     1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     1.6 - *
     1.7 - * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
     1.8 - *
     1.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    1.10 - * Other names may be trademarks of their respective owners.
    1.11 - *
    1.12 - * The contents of this file are subject to the terms of either the GNU
    1.13 - * General Public License Version 2 only ("GPL") or the Common
    1.14 - * Development and Distribution License("CDDL") (collectively, the
    1.15 - * "License"). You may not use this file except in compliance with the
    1.16 - * License. You can obtain a copy of the License at
    1.17 - * http://www.netbeans.org/cddl-gplv2.html
    1.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    1.19 - * specific language governing permissions and limitations under the
    1.20 - * License.  When distributing the software, include this License Header
    1.21 - * Notice in each file and include the License file at
    1.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    1.23 - * particular file as subject to the "Classpath" exception as provided
    1.24 - * by Oracle in the GPL Version 2 section of the License file that
    1.25 - * accompanied this code. If applicable, add the following below the
    1.26 - * License Header, with the fields enclosed by brackets [] replaced by
    1.27 - * your own identifying information:
    1.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    1.29 - *
    1.30 - * If you wish your version of this file to be governed by only the CDDL
    1.31 - * or only the GPL Version 2, indicate your decision by adding
    1.32 - * "[Contributor] elects to include this software in this distribution
    1.33 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    1.34 - * single choice of license, a recipient has the option to distribute
    1.35 - * your version of this file under either the CDDL, the GPL Version 2 or
    1.36 - * to extend the choice of license to its licensees as provided above.
    1.37 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    1.38 - * Version 2 license, then the option applies only if the new code is
    1.39 - * made subject to such option by the copyright holder.
    1.40 - *
    1.41 - * Contributor(s):
    1.42 - *
    1.43 - * Portions Copyrighted 2012 Sun Microsystems, Inc.
    1.44 - */
    1.45 -package org.netbeans.modules.java.hints.test.api;
    1.46 -
    1.47 -import com.sun.source.tree.CompilationUnitTree;
    1.48 -import com.sun.source.util.TreePath;
    1.49 -import java.io.File;
    1.50 -import java.io.FileInputStream;
    1.51 -import java.io.IOException;
    1.52 -import java.io.OutputStream;
    1.53 -import java.lang.ref.Reference;
    1.54 -import java.lang.ref.WeakReference;
    1.55 -import java.net.URL;
    1.56 -import java.util.ArrayList;
    1.57 -import java.util.Arrays;
    1.58 -import java.util.Collection;
    1.59 -import java.util.Collections;
    1.60 -import java.util.Comparator;
    1.61 -import java.util.Enumeration;
    1.62 -import java.util.HashMap;
    1.63 -import java.util.HashSet;
    1.64 -import java.util.IdentityHashMap;
    1.65 -import java.util.LinkedList;
    1.66 -import java.util.List;
    1.67 -import java.util.Map;
    1.68 -import java.util.Map.Entry;
    1.69 -import java.util.Properties;
    1.70 -import java.util.Set;
    1.71 -import java.util.concurrent.atomic.AtomicBoolean;
    1.72 -import java.util.logging.Handler;
    1.73 -import java.util.logging.Level;
    1.74 -import java.util.logging.LogRecord;
    1.75 -import java.util.logging.Logger;
    1.76 -import java.util.prefs.AbstractPreferences;
    1.77 -import java.util.prefs.BackingStoreException;
    1.78 -import java.util.prefs.Preferences;
    1.79 -import java.util.regex.Pattern;
    1.80 -import javax.swing.event.ChangeListener;
    1.81 -import javax.swing.text.Document;
    1.82 -import javax.tools.Diagnostic;
    1.83 -import junit.framework.Assert;
    1.84 -import static junit.framework.Assert.assertEquals;
    1.85 -import static junit.framework.Assert.assertFalse;
    1.86 -import static junit.framework.Assert.assertNotNull;
    1.87 -import static junit.framework.Assert.assertNotSame;
    1.88 -import static junit.framework.Assert.assertTrue;
    1.89 -
    1.90 -import org.netbeans.api.editor.mimelookup.MimeLookup;
    1.91 -import org.netbeans.api.java.classpath.ClassPath;
    1.92 -import org.netbeans.api.java.lexer.JavaTokenId;
    1.93 -import org.netbeans.api.java.queries.SourceForBinaryQuery;
    1.94 -import org.netbeans.api.java.source.ClasspathInfo;
    1.95 -import org.netbeans.api.java.source.CompilationController;
    1.96 -import org.netbeans.api.java.source.CompilationInfo;
    1.97 -import org.netbeans.api.java.source.JavaSource;
    1.98 -import org.netbeans.api.java.source.JavaSource.Phase;
    1.99 -import org.netbeans.api.java.source.ModificationResult;
   1.100 -import org.netbeans.api.java.source.ModificationResult.Difference;
   1.101 -import org.netbeans.api.java.source.Task;
   1.102 -import org.netbeans.api.java.source.WorkingCopy;
   1.103 -import org.netbeans.api.lexer.Language;
   1.104 -import org.netbeans.api.project.ui.*;
   1.105 -import org.netbeans.core.startup.Main;
   1.106 -import org.netbeans.junit.NbTestCase;
   1.107 -import org.netbeans.modules.java.JavaDataLoader;
   1.108 -import org.netbeans.modules.java.hints.providers.code.CodeHintProviderImpl;
   1.109 -import org.netbeans.modules.java.hints.providers.code.FSWrapper;
   1.110 -import org.netbeans.modules.java.hints.providers.code.FSWrapper.ClassWrapper;
   1.111 -import org.netbeans.modules.java.hints.providers.spi.HintDescription;
   1.112 -import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
   1.113 -import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
   1.114 -import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
   1.115 -import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
   1.116 -import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
   1.117 -import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl.Accessor;
   1.118 -import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
   1.119 -import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
   1.120 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch;
   1.121 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
   1.122 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
   1.123 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Resource;
   1.124 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Scope;
   1.125 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.VerifiedSpansCallBack;
   1.126 -import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
   1.127 -import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper;
   1.128 -import org.netbeans.modules.java.hints.spiimpl.batch.Scopes;
   1.129 -import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
   1.130 -import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
   1.131 -import org.netbeans.modules.java.hints.test.Utilities.TestLookup;
   1.132 -import org.netbeans.modules.java.source.JavaSourceAccessor;
   1.133 -import org.netbeans.modules.java.source.TreeLoader;
   1.134 -import org.netbeans.modules.parsing.api.indexing.IndexingManager;
   1.135 -import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
   1.136 -import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
   1.137 -import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
   1.138 -import org.netbeans.spi.editor.hints.ErrorDescription;
   1.139 -import org.netbeans.spi.editor.hints.Fix;
   1.140 -import org.netbeans.spi.editor.hints.Severity;
   1.141 -import org.netbeans.spi.java.classpath.ClassPathProvider;
   1.142 -import org.netbeans.spi.java.classpath.support.ClassPathSupport;
   1.143 -import org.netbeans.spi.java.hints.Hint.Kind;
   1.144 -import org.netbeans.spi.java.hints.HintContext;
   1.145 -import org.netbeans.spi.java.hints.JavaFix;
   1.146 -import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
   1.147 -import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
   1.148 -import org.openide.LifecycleManager;
   1.149 -import org.openide.cookies.EditorCookie;
   1.150 -import org.openide.filesystems.FileObject;
   1.151 -import org.openide.filesystems.FileStateInvalidException;
   1.152 -import org.openide.filesystems.FileSystem;
   1.153 -import org.openide.filesystems.FileUtil;
   1.154 -import org.openide.filesystems.MultiFileSystem;
   1.155 -import org.openide.filesystems.Repository;
   1.156 -import org.openide.filesystems.URLMapper;
   1.157 -import org.openide.filesystems.XMLFileSystem;
   1.158 -import org.openide.loaders.DataObject;
   1.159 -import org.openide.loaders.DataObjectNotFoundException;
   1.160 -import org.openide.util.Exceptions;
   1.161 -import org.openide.util.Lookup;
   1.162 -import org.openide.util.NbBundle;
   1.163 -import org.openide.util.lookup.Lookups;
   1.164 -
   1.165 -/**A support class for writing a test for a Java Hint. A test verifying that correct
   1.166 - * warnings are produced should look like:
   1.167 - * <pre>
   1.168 - * HintTest.create()
   1.169 - *         .input("&lt;input Java source code>")
   1.170 - *         .run(&lt;class containg the hint>)
   1.171 - *         .assertWarnings("&lt;required warning(s)>");
   1.172 - * </pre>
   1.173 - *
   1.174 - * Note: when verifying that no warnings are produced in a particular situation,
   1.175 - * do not pass any warnings to the {@code assertWarnings} method.
   1.176 - *
   1.177 - * A test verifying that a hint's transformation is correct:
   1.178 - * <pre>
   1.179 - * HintTest.create()
   1.180 - *         .input("&lt;input Java source code>")
   1.181 - *         .run(&lt;class containg the hint>)
   1.182 - *         .findWarning("&lt;a warning produce by the hint>")
   1.183 - *         .applyFix() //fill apply the only fix in the given ErrorDescription
   1.184 - *         .assertCompilable()
   1.185 - *         .assertOutput("&lt;output Java source code>");
   1.186 - * </pre>
   1.187 - *
   1.188 - * All the tests run under the {@code test} branding, which allows to specify test values
   1.189 - * for bundle keys for warning and fix in {@code Bundle_test.properties}, to isolate the
   1.190 - * test from changes in the production {@code Bundle.properties}.
   1.191 - *
   1.192 - * @author lahvac
   1.193 - */
   1.194 -public class HintTest {
   1.195 -
   1.196 -    private static final Logger INDEXING_LOGGER = /* RepositoryUpdater.UI_LOGGER */ Logger.getLogger("org.netbeans.ui.indexing");
   1.197 -    static {
   1.198 -        INDEXING_LOGGER.setLevel(Level.WARNING);
   1.199 -    }
   1.200 -
   1.201 -    private final File workDir;
   1.202 -    private final FileObject sourceRoot;
   1.203 -    private final FileObject buildRoot;
   1.204 -    private final FileObject cache;
   1.205 -    private final Preferences testPreferences;
   1.206 -    private final HintsSettings hintSettings;
   1.207 -    private final List<FileObject> checkCompilable = new ArrayList<FileObject>();
   1.208 -    private final List<FileObject> testFiles = new ArrayList<FileObject>();
   1.209 -    private String sourceLevel = "1.5";
   1.210 -    private Character caretMarker;
   1.211 -    private FileObject testFile;
   1.212 -    private int caret = -1;
   1.213 -    private ClassPath sourcePath;
   1.214 -    private ClassPath compileClassPath = ClassPathSupport.createClassPath(new URL[0]);
   1.215 -
   1.216 -    private HintTest() throws Exception {
   1.217 -        List<URL> layers = new LinkedList<URL>();
   1.218 -
   1.219 -        for (String layer : new String[] {"META-INF/generated-layer.xml"}) {
   1.220 -            boolean found = false;
   1.221 -
   1.222 -            for (Enumeration<URL> en = Thread.currentThread().getContextClassLoader().getResources(layer); en.hasMoreElements(); ) {
   1.223 -                found = true;
   1.224 -                layers.add(en.nextElement());
   1.225 -            }
   1.226 -
   1.227 -            Assert.assertTrue(layer, found);
   1.228 -        }
   1.229 -
   1.230 -        XMLFileSystem xmlFS = new XMLFileSystem();
   1.231 -        xmlFS.setXmlUrls(layers.toArray(new URL[0]));
   1.232 -
   1.233 -        FileSystem system = new MultiFileSystem(new FileSystem[] {FileUtil.createMemoryFileSystem(), xmlFS});
   1.234 -
   1.235 -        Repository repository = new Repository(system);
   1.236 -
   1.237 -        assertEquals(Lookup.getDefault().getClass().getCanonicalName(), TestLookup.class, Lookup.getDefault().getClass());
   1.238 -
   1.239 -        ((TestLookup) Lookup.getDefault()).setLookupsImpl(
   1.240 -            Lookups.fixed(repository,
   1.241 -                          new TestProxyClassPathProvider(),
   1.242 -                          new TestSourceForBinaryQuery(),
   1.243 -                          new TestSourceLevelQueryImplementation(),
   1.244 -                          JavaDataLoader.findObject(JavaDataLoader.class, true)),
   1.245 -            Lookups.metaInfServices(HintTest.class.getClassLoader()),
   1.246 -            Lookups.singleton(HintTest.class.getClassLoader())
   1.247 -        );
   1.248 -
   1.249 -        Set<String> amt = MimeTypes.getAllMimeTypes();
   1.250 -        if (amt == null) {
   1.251 -            amt = new HashSet<String>();
   1.252 -        } else {
   1.253 -            amt = new HashSet<String>(amt);
   1.254 -        }
   1.255 -        amt.add("text/x-java");
   1.256 -        MimeTypes.setAllMimeTypes(amt);
   1.257 -        org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
   1.258 -
   1.259 -        TreeLoader.DISABLE_CONFINEMENT_TEST = true;
   1.260 -        testPreferences = new TempPreferences();
   1.261 -        hintSettings = new HintsSettings() {
   1.262 -            @Override public boolean isEnabled(HintMetadata hint) {
   1.263 -                return true;
   1.264 -            }
   1.265 -            @Override public void setEnabled(HintMetadata hint, boolean value) {
   1.266 -                throw new UnsupportedOperationException("Not supported.");
   1.267 -            }
   1.268 -            @Override public Preferences getHintPreferences(HintMetadata hint) {
   1.269 -                return testPreferences;
   1.270 -            }
   1.271 -            @Override public Severity getSeverity(HintMetadata hint) {
   1.272 -                return hint.severity;
   1.273 -            }
   1.274 -            @Override public void setSeverity(HintMetadata hint, Severity severity) {
   1.275 -                throw new UnsupportedOperationException("Not supported.");
   1.276 -            }
   1.277 -        };
   1.278 -
   1.279 -        workDir = getWorkDir();
   1.280 -        deleteSubFiles(workDir);
   1.281 -        FileUtil.refreshFor(workDir);
   1.282 -
   1.283 -        FileObject wd = FileUtil.toFileObject(workDir);
   1.284 -        
   1.285 -        assertNotNull(wd);
   1.286 -
   1.287 -        sourceRoot = FileUtil.createFolder(wd, "src");
   1.288 -        buildRoot = FileUtil.createFolder(wd, "build");
   1.289 -        cache = FileUtil.createFolder(wd, "cache");
   1.290 -
   1.291 -        CacheFolder.setCacheFolder(cache);
   1.292 -
   1.293 -        NbBundle.setBranding("test");
   1.294 -
   1.295 -        sourcePath = ClassPathSupport.createClassPath(sourceRoot);
   1.296 -        
   1.297 -        Main.initializeURLFactory();
   1.298 -    }
   1.299 -
   1.300 -    /**Bootstraps the test framework.
   1.301 -     *
   1.302 -     * @return the test framework - call more methods on it to set-up a test, then call {@code run} method and assert results.
   1.303 -     */
   1.304 -    public static HintTest create() throws Exception {
   1.305 -        return new HintTest();
   1.306 -    }
   1.307 -
   1.308 -    /**A character to use as a marker of a caret in the input code. The caret position
   1.309 -     * during the run method will be set to the position of this character in the first input file.
   1.310 -     *
   1.311 -     * @param c a caret marker
   1.312 -     * @return itself
   1.313 -     */
   1.314 -    public HintTest setCaretMarker(char c) {
   1.315 -        this.caretMarker = c;
   1.316 -        return this;
   1.317 -    }
   1.318 -
   1.319 -    /**Use the specified {@link java.net.URL}s as compile classpath while parsing
   1.320 -     * the Java input. The {@link java.net.URL}s need to be "folder" {@link java.net.URL}s,
   1.321 -     * ready to be passed to {@link ClassPathSupport#createClassPath(java.net.URL[]) }.
   1.322 -     *
   1.323 -     * @param entries that should become roots of the compile classpath
   1.324 -     * @return itself
   1.325 -     * @see FileUtil#urlForArchiveOrDir(java.io.File)
   1.326 -     * @see FileUtil#getArchiveRoot(java.net.URL)
   1.327 -     */
   1.328 -    public HintTest classpath(URL... entries) {
   1.329 -        compileClassPath = ClassPathSupport.createClassPath(entries);
   1.330 -        return this;
   1.331 -    }
   1.332 -
   1.333 -    /**Create a test file. Equivalent to calling {@code input("test/Test.java", code, true)}.
   1.334 -     *
   1.335 -     * @param code the content of the newly created test file
   1.336 -     * @return itself
   1.337 -     */
   1.338 -    public HintTest input(String code) throws Exception {
   1.339 -        return input("test/Test.java", code, true);
   1.340 -    }
   1.341 -
   1.342 -    /**Create a test file. Equivalent to calling {@code input("test/Test.java", code, compilable)}.
   1.343 -     *
   1.344 -     * @param code the content of the newly created test file
   1.345 -     * @param compilable if true, it will be verified that the file does not contain
   1.346 -     *                   compilation errors before the hint is run on it
   1.347 -     * @return itself
   1.348 -     */
   1.349 -    public HintTest input(String code, boolean compilable) throws Exception {
   1.350 -        return input("test/Test.java", code, compilable);
   1.351 -    }
   1.352 -
   1.353 -    /**Create a test file. Equivalent to calling {@code input(fileName, code, true)}.
   1.354 -     *
   1.355 -     * @param fileName a relative file name of the newly created file from a (automatically created) source root
   1.356 -     * @param code the content of the newly created test file
   1.357 -     * @return itself
   1.358 -     */
   1.359 -    public HintTest input(String fileName, String code) throws Exception {
   1.360 -        return input(fileName, code, true);
   1.361 -    }
   1.362 -    
   1.363 -    /**Create a test file. Any number of files can be created for one test, but the hint
   1.364 -     * will be run only on the first one.
   1.365 -     *
   1.366 -     * @param fileName a relative file name of the newly created file from a (automatically created) source root
   1.367 -     * @param code the content of the newly created test file
   1.368 -     * @param compilable if true, it will be verified that the file does not contain
   1.369 -     *                   compilation errors before the hint is run on it
   1.370 -     * @return itself
   1.371 -     */
   1.372 -    public HintTest input(String fileName, String code, boolean compilable) throws Exception {
   1.373 -        int caret = -1;
   1.374 -
   1.375 -        if (caretMarker != null && testFile == null) {
   1.376 -            caret = code.indexOf(caretMarker);
   1.377 -
   1.378 -            assertNotSame("A caret location must be specified", -1, caret);
   1.379 -
   1.380 -            code = code.substring(0, caret) + code.substring(caret + 1);
   1.381 -        }
   1.382 -
   1.383 -        FileObject file = FileUtil.createData(sourceRoot, fileName);
   1.384 -
   1.385 -        copyStringToFile(file, code);
   1.386 -
   1.387 -        if (compilable) {
   1.388 -            checkCompilable.add(file);
   1.389 -        }
   1.390 -
   1.391 -        if (testFile == null) {
   1.392 -            testFile = file;
   1.393 -            this.caret = caret;
   1.394 -        }
   1.395 -        
   1.396 -        testFiles.add(file);
   1.397 -        
   1.398 -        return this;
   1.399 -    }
   1.400 -
   1.401 -    private void ensureCompilable(FileObject file) throws IOException, AssertionError, IllegalArgumentException {
   1.402 -        CompilationInfo info = parse(file);
   1.403 -
   1.404 -        assertNotNull(info);
   1.405 -
   1.406 -        for (Diagnostic d : info.getDiagnostics()) {
   1.407 -            if (d.getKind() == Diagnostic.Kind.ERROR)
   1.408 -                throw new AssertionError(d.getLineNumber() + ":" + d.getColumnNumber() + " " + d.getMessage(null));
   1.409 -        }
   1.410 -    }
   1.411 -
   1.412 -    /**Sets a source level for all Java files used in this test.
   1.413 -     *
   1.414 -     * @param sourceLevel the source level to use while parsing Java files
   1.415 -     * @return itself
   1.416 -     */
   1.417 -    public HintTest sourceLevel(String sourceLevel) {
   1.418 -        this.sourceLevel = sourceLevel;
   1.419 -        return this;
   1.420 -    }
   1.421 -
   1.422 -    /**Sets a preference that will be visible to the hint.
   1.423 -     *
   1.424 -     * @param preferencesKey a key for the preferences
   1.425 -     * @param value the value to set
   1.426 -     * @return itself
   1.427 -     */
   1.428 -    public HintTest preference(String preferencesKey, String value) {
   1.429 -        this.testPreferences.put(preferencesKey, value);
   1.430 -        return this;
   1.431 -    }
   1.432 -
   1.433 -    /**Sets a preference that will be visible to the hint.
   1.434 -     *
   1.435 -     * @param preferencesKey a key for the preferences
   1.436 -     * @param value the value to set
   1.437 -     * @return itself
   1.438 -     */
   1.439 -    public HintTest preference(String preferencesKey, int value) {
   1.440 -        this.testPreferences.putInt(preferencesKey, value);
   1.441 -        return this;
   1.442 -    }
   1.443 -
   1.444 -    /**Sets a preference that will be visible to the hint.
   1.445 -     *
   1.446 -     * @param preferencesKey a key for the preferences
   1.447 -     * @param value the value to set
   1.448 -     * @return itself
   1.449 -     */
   1.450 -    public HintTest preference(String preferencesKey, boolean value) {
   1.451 -        this.testPreferences.putBoolean(preferencesKey, value);
   1.452 -        return this;
   1.453 -    }
   1.454 -    
   1.455 -    /**Runs the given hint(s) on the first file written by a {@code input} method.
   1.456 -     *
   1.457 -     * @param hint all hints in this class will be run on the file
   1.458 -     * @return a wrapper over the hint output that allows verifying results of the hint
   1.459 -     */
   1.460 -    public HintOutput run(Class<?> hint) throws Exception {
   1.461 -        return run(hint, null);
   1.462 -    }
   1.463 -
   1.464 -    /**Runs the given hint(s) on the first file written by a {@code input} method.
   1.465 -     * Runs only hints with the specified {@code hintCode}. Null hintCode includes
   1.466 -     * all hints from the class
   1.467 -     *
   1.468 -     * @param hint all hints in this class will be run on the file
   1.469 -     * @param hintCode if not {@code null}, only hints with the same id will be run
   1.470 -     * @return a wrapper over the hint output that allows verifying results of the hint
   1.471 -     */
   1.472 -    public HintOutput run(Class<?> hint, String hintCode) throws Exception {
   1.473 -        return runImpl(hint, hintCode, new HintComputer() {
   1.474 -            @Override public Collection<ErrorDescription> computeHints(List<HintDescription> total) throws Exception {
   1.475 -                CompilationInfo info = parse(testFile);
   1.476 -
   1.477 -                assertNotNull(info);
   1.478 -
   1.479 -                List<ErrorDescription> result = new ArrayList<ErrorDescription>();
   1.480 -
   1.481 -                Map<HintDescription, List<ErrorDescription>> errors = computeErrors(info, total, new AtomicBoolean());
   1.482 -
   1.483 -                for (Entry<HintDescription, List<ErrorDescription>> e : errors.entrySet()) {
   1.484 -                    result.addAll(e.getValue());
   1.485 -                }
   1.486 -
   1.487 -                Reference<CompilationInfo> infoRef = new WeakReference<CompilationInfo>(info);
   1.488 -                Reference<CompilationUnitTree> cut = new WeakReference<CompilationUnitTree>(info.getCompilationUnit());
   1.489 -
   1.490 -                info = null;
   1.491 -
   1.492 -                DEBUGGING_HELPER.add(result);
   1.493 -                NbTestCase.assertGC("noone holds CompilationInfo", infoRef);
   1.494 -                NbTestCase.assertGC("noone holds javac", cut);
   1.495 -                DEBUGGING_HELPER.remove(result);
   1.496 -
   1.497 -                return result;
   1.498 -            }
   1.499 -        });
   1.500 -    }
   1.501 -
   1.502 -    private HintOutput runImpl(Class<?> hint, String hintCode, HintComputer doComputeErrors) throws Exception {
   1.503 -        IndexingManager.getDefault().refreshIndexAndWait(sourceRoot.toURL(), null);
   1.504 -        
   1.505 -        for (FileObject file : checkCompilable) {
   1.506 -            ensureCompilable(file);
   1.507 -        }
   1.508 -        
   1.509 -        Map<HintMetadata, Collection<HintDescription>> hints = new HashMap<HintMetadata, Collection<HintDescription>>();
   1.510 -        List<ClassWrapper> found = new ArrayList<ClassWrapper>();
   1.511 -
   1.512 -        for (ClassWrapper w : FSWrapper.listClasses()) {
   1.513 -            if (hint.getCanonicalName().equals(w.getName().replace('$', '.'))) {
   1.514 -                found.add(w);
   1.515 -            }
   1.516 -        }
   1.517 -
   1.518 -        assertFalse(found.isEmpty());
   1.519 -
   1.520 -        for (ClassWrapper w : found) {
   1.521 -            CodeHintProviderImpl.processClass(w, hints);
   1.522 -        }
   1.523 -
   1.524 -        List<HintDescription> total = new LinkedList<HintDescription>();
   1.525 -        final Set<ErrorDescription> requiresJavaFix = Collections.newSetFromMap(new IdentityHashMap<ErrorDescription, Boolean>());
   1.526 -
   1.527 -        for (final Entry<HintMetadata, Collection<HintDescription>> e : hints.entrySet()) {
   1.528 -            if (null != hintCode && !e.getKey().id.equals(hintCode)) {
   1.529 -                continue;
   1.530 -            }
   1.531 -            if (   e.getKey().options.contains(Options.NO_BATCH)
   1.532 -                || e.getKey().options.contains(Options.QUERY)
   1.533 -                || e.getKey().kind == Kind.ACTION) {
   1.534 -                total.addAll(e.getValue());
   1.535 -                continue;
   1.536 -            }
   1.537 -            for (final HintDescription hd : e.getValue()) {
   1.538 -                total.add(HintDescriptionFactory.create()
   1.539 -                                               .setTrigger(hd.getTrigger())
   1.540 -                                               .setMetadata(e.getKey())
   1.541 -                                               .setAdditionalConstraints(hd.getAdditionalConstraints())
   1.542 -                                               .addOptions(hd.getOptions().toArray(new Options[0]))
   1.543 -                                               .setWorker(new Worker() {
   1.544 -                                                    @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
   1.545 -                                                        Collection<? extends ErrorDescription> errors = hd.getWorker().createErrors(ctx);
   1.546 - 
   1.547 -                                                        if (errors != null) {
   1.548 -                                                            for (ErrorDescription ed : errors) {
   1.549 -                                                                requiresJavaFix.add(ed);
   1.550 -                                                            }
   1.551 -                                                        }
   1.552 -                                                        
   1.553 -                                                        return errors;
   1.554 -                                                     }
   1.555 -                                                })
   1.556 -                                              .produce());
   1.557 -            }
   1.558 -        }
   1.559 -        
   1.560 -        Handler h = new Handler() {
   1.561 -            @Override public void publish(LogRecord record) {
   1.562 -                if (   record.getLevel().intValue() >= Level.WARNING.intValue()
   1.563 -                    && record.getThrown() != null) {
   1.564 -                    throw new IllegalStateException(record.getThrown());
   1.565 -                }
   1.566 -            }
   1.567 -            @Override public void flush() { }
   1.568 -            @Override public void close() throws SecurityException { }
   1.569 -        };
   1.570 -
   1.571 -        Logger log = Logger.getLogger(Exceptions.class.getName());
   1.572 -        log.addHandler(h);
   1.573 -        List<ErrorDescription> result = new ArrayList<ErrorDescription>(doComputeErrors.computeHints(total));
   1.574 -        log.removeHandler(h);
   1.575 -
   1.576 -        Collections.sort(result, ERRORS_COMPARATOR);
   1.577 -        
   1.578 -        return new HintOutput(result, requiresJavaFix);
   1.579 -    }
   1.580 -
   1.581 -    private interface HintComputer {
   1.582 -        public Collection<ErrorDescription> computeHints(List<HintDescription> total) throws Exception;
   1.583 -    }
   1.584 -    
   1.585 -    public HintOutput runGlobal(Class<?> hint) throws Exception {
   1.586 -        return runImpl(hint, null, new HintComputer() {
   1.587 -            @Override public Collection<ErrorDescription> computeHints(List<HintDescription> total) throws Exception {
   1.588 -                final List<ErrorDescription> result = new ArrayList<ErrorDescription>();
   1.589 -                Scope s = Scopes.specifiedFoldersScope(Folder.convert(sourceRoot));
   1.590 -                BatchResult batchResult = BatchSearch.findOccurrences(total, s);
   1.591 -                BatchSearch.getVerifiedSpans(batchResult, new ProgressHandleWrapper(1, 1), new VerifiedSpansCallBack() {
   1.592 -                    @Override public void groupStarted() { }
   1.593 -                    @Override public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
   1.594 -                        result.addAll(hints);
   1.595 -                        return true;
   1.596 -                    }
   1.597 -                    @Override public void groupFinished() { }
   1.598 -                    @Override public void cannotVerifySpan(Resource r) { }
   1.599 -                }, false, new ArrayList<MessageImpl>(), new AtomicBoolean());
   1.600 -
   1.601 -                return result;
   1.602 -            }
   1.603 -        });
   1.604 -    }
   1.605 -    
   1.606 -    //must keep the error descriptions (and their Fixes through them) in a field
   1.607 -    //so that assertGC is able to provide a useful trace of references:
   1.608 -    private static Set<List<ErrorDescription>> DEBUGGING_HELPER = Collections.newSetFromMap(new IdentityHashMap<List<ErrorDescription>, Boolean>());
   1.609 -
   1.610 -    private CompilationInfo parse(FileObject file) throws DataObjectNotFoundException, IllegalArgumentException, IOException {
   1.611 -        DataObject od = DataObject.find(file);
   1.612 -        EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
   1.613 -
   1.614 -        assertNotNull(ec);
   1.615 -
   1.616 -        Document doc = ec.openDocument();
   1.617 -
   1.618 -        doc.putProperty(Language.class, JavaTokenId.language());
   1.619 -        doc.putProperty("mimeType", "text/x-java");
   1.620 -
   1.621 -        JavaSource js = JavaSource.create(ClasspathInfo.create(file), file);
   1.622 -
   1.623 -        assertNotNull("found JavaSource for " + file, js);
   1.624 -
   1.625 -        final DeadlockTask bt = new DeadlockTask(Phase.RESOLVED);
   1.626 -
   1.627 -        js.runUserActionTask(bt, true);
   1.628 -        
   1.629 -        return bt.info;
   1.630 -    }
   1.631 -
   1.632 -    private Map<HintDescription, List<ErrorDescription>> computeErrors(CompilationInfo info, Iterable<? extends HintDescription> hints, AtomicBoolean cancel) {
   1.633 -        return new HintsInvoker(hintSettings, caret, cancel).computeHints(info, new TreePath(info.getCompilationUnit()), hints, new LinkedList<MessageImpl>());
   1.634 -    }
   1.635 -
   1.636 -    FileObject getSourceRoot() {
   1.637 -        return sourceRoot;
   1.638 -    }
   1.639 -
   1.640 -    private static class TempPreferences extends AbstractPreferences {
   1.641 -
   1.642 -        /*private*/Properties properties;
   1.643 -
   1.644 -        private TempPreferences() {
   1.645 -            super(null, "");
   1.646 -        }
   1.647 -
   1.648 -        private  TempPreferences(TempPreferences parent, String name)  {
   1.649 -            super(parent, name);
   1.650 -            newNode = true;
   1.651 -        }
   1.652 -
   1.653 -        protected final String getSpi(String key) {
   1.654 -            return properties().getProperty(key);
   1.655 -        }
   1.656 -
   1.657 -        protected final String[] childrenNamesSpi() throws BackingStoreException {
   1.658 -            return new String[0];
   1.659 -        }
   1.660 -
   1.661 -        protected final String[] keysSpi() throws BackingStoreException {
   1.662 -            return properties().keySet().toArray(new String[0]);
   1.663 -        }
   1.664 -
   1.665 -        protected final void putSpi(String key, String value) {
   1.666 -            properties().put(key,value);
   1.667 -        }
   1.668 -
   1.669 -        protected final void removeSpi(String key) {
   1.670 -            properties().remove(key);
   1.671 -        }
   1.672 -
   1.673 -        protected final void removeNodeSpi() throws BackingStoreException {}
   1.674 -        protected  void flushSpi() throws BackingStoreException {}
   1.675 -        protected void syncSpi() throws BackingStoreException {
   1.676 -            properties().clear();
   1.677 -        }
   1.678 -
   1.679 -        @Override
   1.680 -        public void put(String key, String value) {
   1.681 -            try {
   1.682 -                super.put(key, value);
   1.683 -            } catch (IllegalArgumentException iae) {
   1.684 -                if (iae.getMessage().contains("too long")) {
   1.685 -                    // Not for us!
   1.686 -                    putSpi(key, value);
   1.687 -                } else {
   1.688 -                    throw iae;
   1.689 -                }
   1.690 -            }
   1.691 -        }
   1.692 -
   1.693 -        Properties properties()  {
   1.694 -            if (properties == null) {
   1.695 -                properties = new Properties();
   1.696 -            }
   1.697 -            return properties;
   1.698 -        }
   1.699 -
   1.700 -        protected AbstractPreferences childSpi(String name) {
   1.701 -            return new TempPreferences(this, name);
   1.702 -        }
   1.703 -    }
   1.704 -
   1.705 -    private class TestSourceForBinaryQuery implements SourceForBinaryQueryImplementation {
   1.706 -
   1.707 -        public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
   1.708 -            FileObject f = URLMapper.findFileObject(binaryRoot);
   1.709 -
   1.710 -            if (buildRoot.equals(f)) {
   1.711 -                return new SourceForBinaryQuery.Result() {
   1.712 -                    public FileObject[] getRoots() {
   1.713 -                        return new FileObject[] {
   1.714 -                            sourceRoot,
   1.715 -                        };
   1.716 -                    }
   1.717 -
   1.718 -                    public void addChangeListener(ChangeListener l) {
   1.719 -                    }
   1.720 -
   1.721 -                    public void removeChangeListener(ChangeListener l) {
   1.722 -                    }
   1.723 -                };
   1.724 -            }
   1.725 -
   1.726 -            return null;
   1.727 -        }
   1.728 -
   1.729 -    }
   1.730 -
   1.731 -    private static List<URL> bootClassPath;
   1.732 -
   1.733 -    private static Logger log = Logger.getLogger(HintTest.class.getName());
   1.734 -
   1.735 -    private static synchronized List<URL> getBootClassPath() {
   1.736 -        if (bootClassPath == null) {
   1.737 -            try {
   1.738 -                String cp = System.getProperty("sun.boot.class.path");
   1.739 -                List<URL> urls = new ArrayList<URL>();
   1.740 -                String[] paths = cp.split(Pattern.quote(System.getProperty("path.separator")));
   1.741 -
   1.742 -                for (String path : paths) {
   1.743 -                    File f = new File(path);
   1.744 -
   1.745 -                    if (!f.canRead())
   1.746 -                        continue;
   1.747 -
   1.748 -                    FileObject fo = FileUtil.toFileObject(f);
   1.749 -
   1.750 -                    if (FileUtil.isArchiveFile(fo)) {
   1.751 -                        fo = FileUtil.getArchiveRoot(fo);
   1.752 -                    }
   1.753 -
   1.754 -                    if (fo != null) {
   1.755 -                        urls.add(fo.getURL());
   1.756 -                    }
   1.757 -                }
   1.758 -
   1.759 -                bootClassPath = urls;
   1.760 -            } catch (FileStateInvalidException e) {
   1.761 -                if (log.isLoggable(Level.SEVERE))
   1.762 -                    log.log(Level.SEVERE, e.getMessage(), e);
   1.763 -            }
   1.764 -        }
   1.765 -
   1.766 -        return bootClassPath;
   1.767 -    }
   1.768 -    
   1.769 -    private class TestProxyClassPathProvider implements ClassPathProvider {
   1.770 -
   1.771 -        public ClassPath findClassPath(FileObject file, String type) {
   1.772 -            try {
   1.773 -            if (ClassPath.BOOT == type) {
   1.774 -                // XXX simpler to use JavaPlatformManager.getDefault().getDefaultPlatform().getBootstrapLibraries()
   1.775 -                return ClassPathSupport.createClassPath(getBootClassPath().toArray(new URL[0]));
   1.776 -            }
   1.777 -
   1.778 -            if (ClassPath.SOURCE == type) {
   1.779 -                return sourcePath;
   1.780 -            }
   1.781 -
   1.782 -            if (ClassPath.COMPILE == type) {
   1.783 -                return compileClassPath;
   1.784 -            }
   1.785 -
   1.786 -            if (ClassPath.EXECUTE == type) {
   1.787 -                return ClassPathSupport.createClassPath(new FileObject[] {
   1.788 -                    buildRoot
   1.789 -                });
   1.790 -            }
   1.791 -            } catch (Exception e) {
   1.792 -                e.printStackTrace();
   1.793 -            }
   1.794 -            return null;
   1.795 -        }
   1.796 -
   1.797 -    }
   1.798 -
   1.799 -    private class TestSourceLevelQueryImplementation implements SourceLevelQueryImplementation {
   1.800 -
   1.801 -        public String getSourceLevel(FileObject javaFile) {
   1.802 -            return sourceLevel;
   1.803 -        }
   1.804 -
   1.805 -    }
   1.806 -
   1.807 -
   1.808 -    private static class DeadlockTask implements Task<CompilationController> {
   1.809 -
   1.810 -        private final Phase phase;
   1.811 -        private CompilationInfo info;
   1.812 -
   1.813 -        public DeadlockTask(Phase phase) {
   1.814 -            assert phase != null;
   1.815 -            this.phase = phase;
   1.816 -        }
   1.817 -
   1.818 -        public void run( CompilationController info ) {
   1.819 -            try {
   1.820 -                info.toPhase(this.phase);
   1.821 -                this.info = info;
   1.822 -            } catch (IOException ioe) {
   1.823 -                if (log.isLoggable(Level.SEVERE))
   1.824 -                    log.log(Level.SEVERE, ioe.getMessage(), ioe);
   1.825 -            }
   1.826 -        }
   1.827 -
   1.828 -    }
   1.829 -
   1.830 -    /**Encapsulated the output of the hint.
   1.831 -     */
   1.832 -    public final class HintOutput {
   1.833 -        
   1.834 -        private final List<ErrorDescription> errors;
   1.835 -        private final Set<ErrorDescription> requiresJavaFix;
   1.836 -
   1.837 -        private HintOutput(List<ErrorDescription> errors, Set<ErrorDescription> requiresJavaFix) {
   1.838 -            this.errors = errors;
   1.839 -            this.requiresJavaFix = requiresJavaFix;
   1.840 -
   1.841 -        }
   1.842 -
   1.843 -        /**Assert that the hint(s) produced the given warnings. The provided strings
   1.844 -         * should match {@code toString()} results of {@link ErrorDescription}s produced
   1.845 -         * by the hint(s).
   1.846 -         *
   1.847 -         * @param warnings expected {@code toString()} results of {@link ErrorDescription}s produced
   1.848 -         *                 by the hint
   1.849 -         * @return itself
   1.850 -         * @throws AssertionError if the given warnings do not match the actual warnings
   1.851 -         */
   1.852 -        public HintOutput assertWarnings(String... warnings) {
   1.853 -            assertEquals("The warnings provided by the hint do not match expected warnings.", Arrays.toString(warnings), errors.toString());
   1.854 -
   1.855 -            return this;
   1.856 -        }
   1.857 -
   1.858 -        /**Assert that the hint(s) produced warnings include the given warnings. The provided strings
   1.859 -         * should match {@code toString()} results of {@link ErrorDescription}s produced
   1.860 -         * by the hint(s).
   1.861 -         *
   1.862 -         * @param warnings expected {@code toString()} results of {@link ErrorDescription}s produced
   1.863 -         *                 by the hint
   1.864 -         * @return itself
   1.865 -         * @throws AssertionError if the given warnings do not match the actual warnings
   1.866 -         */
   1.867 -        public HintOutput assertContainsWarnings(String... warnings) {
   1.868 -            Set<String> goldenSet = new HashSet<String>(Arrays.asList(warnings));
   1.869 -            List<String> errorsNames = new LinkedList<String>();
   1.870 -
   1.871 -            for (ErrorDescription d : errors) {
   1.872 -                goldenSet.remove(d.toString());
   1.873 -                errorsNames.add(d.toString());
   1.874 -            }
   1.875 -            
   1.876 -            assertTrue("The warnings provided by the hint do not contain expected warnings. Provided warnings: " + errorsNames.toString(), goldenSet.isEmpty());
   1.877 -
   1.878 -            return this;
   1.879 -        }
   1.880 -
   1.881 -        /**Assert that the hint(s) produced warnings do not include the given warnings. The provided strings
   1.882 -         * should match {@code toString()} results of {@link ErrorDescription}s produced
   1.883 -         * by the hint(s).
   1.884 -         *
   1.885 -         * @param warnings expected {@code toString()} results of {@link ErrorDescription}s produced
   1.886 -         *                 by the hint
   1.887 -         * @return itself
   1.888 -         * @throws AssertionError if the given warnings do not match the actual warnings
   1.889 -         */
   1.890 -        public HintOutput assertNotContainsWarnings(String... warnings) {
   1.891 -            Set<String> goldenSet = new HashSet<String>(Arrays.asList(warnings));
   1.892 -            List<String> errorsNames = new LinkedList<String>();
   1.893 -
   1.894 -            boolean fail = false;
   1.895 -            for (ErrorDescription d : errors) {
   1.896 -                if (goldenSet.remove(d.getDescription()))
   1.897 -                    fail = true;
   1.898 -                errorsNames.add(d.toString());
   1.899 -            }
   1.900 -            
   1.901 -            assertFalse("The warnings provided by the hint do not exclude expected warnings. Provided warnings: " + errorsNames.toString(), fail);
   1.902 -
   1.903 -            return this;
   1.904 -        }
   1.905 -        
   1.906 -        /**Find a specific warning.
   1.907 -         *
   1.908 -         * @param warning the warning to find - must be equivalent to {@code toString()}
   1.909 -         *                results of the {@link ErrorDescription}.
   1.910 -         * @return a wrapper about the given specific warnings
   1.911 -         * @throws AssertionError if the given warning cannot be found
   1.912 -         */
   1.913 -        public HintWarning findWarning(String warning) {
   1.914 -            ErrorDescription toFix = null;
   1.915 -
   1.916 -            for (ErrorDescription d : errors) {
   1.917 -                if (warning.equals(d.toString())) {
   1.918 -                    toFix = d;
   1.919 -                    break;
   1.920 -                }
   1.921 -            }
   1.922 -
   1.923 -            assertNotNull("Warning: \"" + warning + "\" not found. All ErrorDescriptions: " + errors.toString(), toFix);
   1.924 -
   1.925 -            return new HintWarning(toFix, requiresJavaFix.contains(toFix));
   1.926 -        }
   1.927 -    }
   1.928 -
   1.929 -    /**A wrapper over a single warning.
   1.930 -     */
   1.931 -    public final class HintWarning {
   1.932 -        private final ErrorDescription warning;
   1.933 -        private final boolean requiresJavaFix;
   1.934 -        HintWarning(ErrorDescription warning, boolean requiresJavaFix) {
   1.935 -            this.warning = warning;
   1.936 -            this.requiresJavaFix = requiresJavaFix;
   1.937 -        }
   1.938 -        /**Applies the only fix of the current warning. Fails if the given warning
   1.939 -         * does not have exactly one fix.
   1.940 -         *
   1.941 -         * Note this is a destructive operation - the {@link #run(java.lang.Class)} or {@link #applyFix}
   1.942 -         * cannot be run in the future on any object that follows the chain from the same invocation of {@link #create()}.
   1.943 -         *
   1.944 -         * @return a wrapper over resulting source code
   1.945 -         * @throws AssertionError if there is not one fix for the given {@link ErrorDescription}
   1.946 -         */
   1.947 -        public AppliedFix applyFix() throws Exception {
   1.948 -            return applyFix(true);
   1.949 -        }
   1.950 -
   1.951 -        AppliedFix applyFix(boolean saveAll) throws Exception {
   1.952 -            assertTrue("Must be computed", warning.getFixes().isComputed());
   1.953 -
   1.954 -            List<Fix> fixes = warning.getFixes().getFixes();
   1.955 -
   1.956 -            assertEquals(1, fixes.size());
   1.957 -
   1.958 -            doApplyFix(fixes.get(0));
   1.959 -
   1.960 -            if (saveAll)
   1.961 -                LifecycleManager.getDefault().saveAll();
   1.962 -            
   1.963 -            return new AppliedFix();
   1.964 -        }
   1.965 -        /**Applies the specified fix of the current warning.
   1.966 -         *
   1.967 -         * Note this is a destructive operation - the {@link #run(java.lang.Class)} or {@link #applyFix}
   1.968 -         * cannot be run in the future on any object that follows the chain from the same invocation of {@link #create()}.
   1.969 -         *
   1.970 -         * @param fix {@link Fix#getText() } result of the required fix
   1.971 -         * @return a wrapper over resulting source code
   1.972 -         * @throws AssertionError if the fix cannot be found
   1.973 -         */
   1.974 -        public AppliedFix applyFix(String fix) throws Exception {
   1.975 -            assertTrue("Must be computed", warning.getFixes().isComputed());
   1.976 -
   1.977 -            List<Fix> fixes = warning.getFixes().getFixes();
   1.978 -            List<String> fixNames = new LinkedList<String>();
   1.979 -            Fix toApply = null;
   1.980 -
   1.981 -            for (Fix f : fixes) {
   1.982 -                if (fix.equals(f.getText())) {
   1.983 -                    toApply = f;
   1.984 -                }
   1.985 -
   1.986 -                fixNames.add(f.getText());
   1.987 -            }
   1.988 -
   1.989 -            assertNotNull("Cannot find fix to invoke: " + fixNames.toString(), toApply);
   1.990 -
   1.991 -            doApplyFix(toApply);
   1.992 -            
   1.993 -            LifecycleManager.getDefault().saveAll();
   1.994 -
   1.995 -            return new AppliedFix();
   1.996 -        }
   1.997 -        private void doApplyFix(Fix f) throws Exception {
   1.998 -            Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
   1.999 -            preferences.putBoolean("importInnerClasses", true);
  1.1000 -            try {
  1.1001 -                if (requiresJavaFix) {
  1.1002 -                    assertTrue("The fix must be a JavaFix", f instanceof JavaFixImpl);
  1.1003 -                    
  1.1004 -                    ModificationResult result1 = runJavaFix(((JavaFixImpl) f).jf);
  1.1005 -                    ModificationResult result2 = runJavaFix(((JavaFixImpl) f).jf);
  1.1006 -                    
  1.1007 -                    //ensure the results are the same:
  1.1008 -                    assertEquals("The fix must be repeatable", result1.getModifiedFileObjects(), result2.getModifiedFileObjects());
  1.1009 -                    
  1.1010 -                    for (FileObject file : result1.getModifiedFileObjects()) {
  1.1011 -                        assertEquals("The fix must be repeatable", result1.getResultingSource(file), result2.getResultingSource(file));
  1.1012 -                    }
  1.1013 -                    
  1.1014 -                    result1.commit();
  1.1015 -                } else {
  1.1016 -                    f.implement();
  1.1017 -                }
  1.1018 -            } finally {
  1.1019 -                preferences.remove("importInnerClasses");
  1.1020 -            }
  1.1021 -        }
  1.1022 -        private ModificationResult runJavaFix(final JavaFix jf) throws IOException {
  1.1023 -            FileObject file = Accessor.INSTANCE.getFile(jf);
  1.1024 -            JavaSource js = JavaSource.forFileObject(file);
  1.1025 -            final Map<FileObject, List<Difference>> changes = new HashMap<FileObject, List<Difference>>();
  1.1026 -
  1.1027 -            ModificationResult mr = js.runModificationTask(new Task<WorkingCopy>() {
  1.1028 -                public void run(WorkingCopy wc) throws Exception {
  1.1029 -                    if (wc.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
  1.1030 -                        return;
  1.1031 -                    }
  1.1032 -
  1.1033 -                    Map<FileObject, byte[]> resourceContentChanges = new HashMap<FileObject, byte[]>();
  1.1034 -                    Accessor.INSTANCE.process(jf, wc, true, resourceContentChanges, /*Ignored for now:*/new ArrayList<RefactoringElementImplementation>());
  1.1035 -                    BatchUtilities.addResourceContentChanges(resourceContentChanges, changes);
  1.1036 -                    
  1.1037 -                }
  1.1038 -            });
  1.1039 -            
  1.1040 -            changes.putAll(JavaSourceAccessor.getINSTANCE().getDiffsFromModificationResult(mr));
  1.1041 -            
  1.1042 -            return JavaSourceAccessor.getINSTANCE().createModificationResult(changes, Collections.<Object, int[]>emptyMap());
  1.1043 -        }
  1.1044 -        /**Verifies that the current warning provides the given fixes.
  1.1045 -         *
  1.1046 -         * @param fixes the {@link Fix#getText() } of the expected fixes
  1.1047 -         * @return itself
  1.1048 -         * @throws AssertionError if the expected fixes do not match the provided fixes
  1.1049 -         * @since 1.1
  1.1050 -         */
  1.1051 -        public HintWarning assertFixes(String... expectedFixes) throws Exception {
  1.1052 -            assertTrue("Must be computed", warning.getFixes().isComputed());
  1.1053 -
  1.1054 -            List<String> fixNames = new LinkedList<String>();
  1.1055 -
  1.1056 -            for (Fix f : warning.getFixes().getFixes()) {
  1.1057 -                if (f instanceof SyntheticFix) continue;
  1.1058 -                fixNames.add(f.getText());
  1.1059 -            }
  1.1060 -
  1.1061 -            assertEquals("Fixes for the current warning do not match the expected fixes. All fixes: " + fixNames.toString(), Arrays.asList(expectedFixes), fixNames);
  1.1062 -
  1.1063 -            return this;
  1.1064 -        }
  1.1065 -    }
  1.1066 -
  1.1067 -    /**A wrapper over result after applying a fix.
  1.1068 -     */
  1.1069 -    public final class AppliedFix {
  1.1070 -        /**Require that the result is compilable. Equivalent to {@code assertCompilable("test/Test.java")}
  1.1071 -         *
  1.1072 -         * @return the wrapper itself
  1.1073 -         * @throws AssertionError if the result is not compilable
  1.1074 -         */
  1.1075 -        public AppliedFix assertCompilable() throws Exception {
  1.1076 -            return assertCompilable("test/Test.java");
  1.1077 -        }
  1.1078 -        /**Require that the given resulting file is compilable.
  1.1079 -         *
  1.1080 -         * @param fileName the name of the file that should be verified
  1.1081 -         * @return the wrapper itself
  1.1082 -         * @throws AssertionError if the result is not compilable
  1.1083 -         */
  1.1084 -        public AppliedFix assertCompilable(String fileName) throws Exception {
  1.1085 -            FileObject toCheck = sourceRoot.getFileObject(fileName);
  1.1086 -
  1.1087 -            assertNotNull(toCheck);
  1.1088 -
  1.1089 -            ensureCompilable(toCheck);
  1.1090 -            return this;
  1.1091 -        }
  1.1092 -        /**Verify the content of the resulting file. Equivalent to {@code assertOutput("test/Test.java")}.
  1.1093 -         *
  1.1094 -         * This method will "normalize" whitespaces in the file: generally, all
  1.1095 -         * whitespaces are reduced to a single space both in the given code and
  1.1096 -         * the code read from the file, before the comparison.
  1.1097 -         *
  1.1098 -         * @param code expected content of the resulting file.
  1.1099 -         * @return the wrapper itself
  1.1100 -         * @throws AssertionError if the file does not have the correct content
  1.1101 -         */
  1.1102 -        public AppliedFix assertOutput(String code) throws Exception {
  1.1103 -            return assertOutput("test/Test.java", code);
  1.1104 -        }
  1.1105 -        /**Verify the content of the given resulting file.
  1.1106 -         *
  1.1107 -         * This method will "normalize" whitespaces in the file: generally, all
  1.1108 -         * whitespaces are reduced to a single space both in the given code and
  1.1109 -         * the code read from the file, before the comparison.
  1.1110 -         *
  1.1111 -         * @param fileName the name of the file that should be verified
  1.1112 -         * @param code expected content of the resulting file.
  1.1113 -         * @return the wrapper itself
  1.1114 -         * @throws AssertionError if the file does not have the correct content
  1.1115 -         */
  1.1116 -        public AppliedFix assertOutput(String fileName, String code) throws Exception {
  1.1117 -            FileObject toCheck = sourceRoot.getFileObject(fileName);
  1.1118 -
  1.1119 -            assertNotNull("Required file: " + fileName + " not found", toCheck);
  1.1120 -
  1.1121 -            DataObject toCheckDO = DataObject.find(toCheck);
  1.1122 -            EditorCookie ec = toCheckDO.getLookup().lookup(EditorCookie.class);
  1.1123 -            Document toCheckDocument = ec.openDocument();
  1.1124 -
  1.1125 -            String realCode = toCheckDocument.getText(0, toCheckDocument.getLength());
  1.1126 -
  1.1127 -            //ignore whitespaces:
  1.1128 -            realCode = reduceWhitespaces(realCode);
  1.1129 -
  1.1130 -            assertEquals("The output code does not match the expected code.", reduceWhitespaces(code), realCode);
  1.1131 -
  1.1132 -            return this;
  1.1133 -        }
  1.1134 -        
  1.1135 -        private String reduceWhitespaces(String str) {
  1.1136 -            StringBuilder result = new StringBuilder();
  1.1137 -            int i = 0;
  1.1138 -            boolean wasWhitespace = false;
  1.1139 -            
  1.1140 -            while (i < str.length()) {
  1.1141 -                int codePoint = str.codePointAt(i);
  1.1142 -                
  1.1143 -                if (Character.isWhitespace(codePoint)) {
  1.1144 -                    if (!wasWhitespace) {
  1.1145 -                        result.append(" ");
  1.1146 -                        wasWhitespace = true;
  1.1147 -                    }
  1.1148 -                } else {
  1.1149 -                    result.appendCodePoint(codePoint);
  1.1150 -                    wasWhitespace = false;
  1.1151 -                }
  1.1152 -                i += Character.charCount(codePoint);
  1.1153 -            }
  1.1154 -            
  1.1155 -            return result.toString();
  1.1156 -        }
  1.1157 -        
  1.1158 -        /**Verify the content of the resulting file. Equivalent to {@code assertVerbatimOutput("test/Test.java")}.
  1.1159 -         *
  1.1160 -         * This method will compare the content of the file exactly with the provided
  1.1161 -         * code.
  1.1162 -         *
  1.1163 -         * @param fileName the name of the file that should be verified
  1.1164 -         * @param code expected content of the resulting file.
  1.1165 -         * @return the wrapper itself
  1.1166 -         * @throws AssertionError if the result is not compilable
  1.1167 -         */
  1.1168 -        public AppliedFix assertVerbatimOutput(String code) throws Exception {
  1.1169 -            return assertVerbatimOutput("test/Test.java", code);
  1.1170 -        }
  1.1171 -        /**Verify the content of the given resulting file.
  1.1172 -         *
  1.1173 -         * This method will compare the content of the file exactly with the provided
  1.1174 -         * code.
  1.1175 -         *
  1.1176 -         * @param fileName the name of the file that should be verified
  1.1177 -         * @param code expected content of the resulting file.
  1.1178 -         * @return the wrapper itself
  1.1179 -         * @throws AssertionError if the result is not compilable
  1.1180 -         */
  1.1181 -        public AppliedFix assertVerbatimOutput(String fileName, String code) throws Exception {
  1.1182 -            FileObject toCheck = sourceRoot.getFileObject(fileName);
  1.1183 -
  1.1184 -            assertNotNull(toCheck);
  1.1185 -
  1.1186 -            DataObject toCheckDO = DataObject.find(toCheck);
  1.1187 -            EditorCookie ec = toCheckDO.getLookup().lookup(EditorCookie.class);
  1.1188 -            Document toCheckDocument = ec.openDocument();
  1.1189 -
  1.1190 -            String realCode = toCheckDocument.getText(0, toCheckDocument.getLength());
  1.1191 -
  1.1192 -            assertEquals("The output code does not match the expected code.", code, realCode);
  1.1193 -
  1.1194 -            return this;
  1.1195 -        }
  1.1196 -
  1.1197 -        /**Return code after the fix has been applied.
  1.1198 -         *
  1.1199 -         * @return the code after the fix has been applied
  1.1200 -         */
  1.1201 -        public String getOutput() throws Exception {
  1.1202 -            return getOutput("test/Test.java");
  1.1203 -        }
  1.1204 -
  1.1205 -        /**Return code after the fix has been applied.
  1.1206 -         *
  1.1207 -         * @param fileName file for which the code should be returned
  1.1208 -         * @return the code after the fix has been applied
  1.1209 -         */
  1.1210 -        public String getOutput(String fileName) throws Exception {
  1.1211 -            FileObject toCheck = sourceRoot.getFileObject(fileName);
  1.1212 -
  1.1213 -            assertNotNull(toCheck);
  1.1214 -
  1.1215 -            DataObject toCheckDO = DataObject.find(toCheck);
  1.1216 -            EditorCookie ec = toCheckDO.getLookup().lookup(EditorCookie.class);
  1.1217 -            Document toCheckDocument = ec.openDocument();
  1.1218 -
  1.1219 -            return toCheckDocument.getText(0, toCheckDocument.getLength());
  1.1220 -        }
  1.1221 -    }
  1.1222 -
  1.1223 -    private static final Comparator<ErrorDescription> ERRORS_COMPARATOR = new Comparator<ErrorDescription> () {
  1.1224 -
  1.1225 -        public int compare (ErrorDescription e1, ErrorDescription e2) {
  1.1226 -            return e1.getRange ().getBegin ().getOffset () - e2.getRange ().getBegin ().getOffset ();
  1.1227 -        }
  1.1228 -    };
  1.1229 -
  1.1230 -    static {
  1.1231 -        System.setProperty("org.openide.util.Lookup", TestLookup.class.getName());
  1.1232 -        Assert.assertEquals(TestLookup.class, Lookup.getDefault().getClass());
  1.1233 -    }
  1.1234 -
  1.1235 -    //workdir computation (copied from NbTestCase):
  1.1236 -    private static File getWorkDir() throws IOException {
  1.1237 -        // now we have path, so if not available, create workdir
  1.1238 -        File workdir = FileUtil.normalizeFile(new File(getWorkDirPath()));
  1.1239 -        if (workdir.exists()) {
  1.1240 -            if (!workdir.isDirectory()) {
  1.1241 -                // work dir exists, but is not directory - this should not happen
  1.1242 -                // trow exception
  1.1243 -                throw new IOException("workdir exists, but is not a directory, workdir = " + workdir);
  1.1244 -            } else {
  1.1245 -                // everything looks correctly, return the path
  1.1246 -                return workdir;
  1.1247 -            }
  1.1248 -        } else {
  1.1249 -            // we need to create it
  1.1250 -            boolean result = workdir.mkdirs();
  1.1251 -            if (result == false) {
  1.1252 -                // mkdirs() failed - throw an exception
  1.1253 -                throw new IOException("workdir creation failed: " + workdir);
  1.1254 -            } else {
  1.1255 -                // everything looks ok - return path
  1.1256 -                return workdir;
  1.1257 -            }
  1.1258 -        }
  1.1259 -    }
  1.1260 -
  1.1261 -    private static String getWorkDirPath() {
  1.1262 -        StackTraceElement caller = null;
  1.1263 -        boolean seenItself = false;
  1.1264 -        
  1.1265 -        for (StackTraceElement e : new Exception().getStackTrace()) {
  1.1266 -            if (HintTest.class.getName().equals(e.getClassName())) seenItself = true;
  1.1267 -            if (seenItself && !HintTest.class.getName().equals(e.getClassName())) {
  1.1268 -                caller = e;
  1.1269 -                break;
  1.1270 -            }
  1.1271 -        }
  1.1272 -        
  1.1273 -        String name = caller != null ? caller.getMethodName() : "unknownTest";
  1.1274 -        // start - PerformanceTestCase overrides getName() method and then
  1.1275 -        // name can contain illegal characters
  1.1276 -        String osName = System.getProperty("os.name");
  1.1277 -        if (osName != null && osName.startsWith("Windows")) {
  1.1278 -            char ntfsIllegal[] ={'"','/','\\','?','<','>','|',':'};
  1.1279 -            for (int i=0; i<ntfsIllegal.length; i++) {
  1.1280 -                name = name.replace(ntfsIllegal[i], '~');
  1.1281 -            }
  1.1282 -        }
  1.1283 -        // end
  1.1284 -        
  1.1285 -        final String workDirPath = getWorkDirPathFromManager();
  1.1286 -        
  1.1287 -        // #94319 - shorten workdir path if the following is too long
  1.1288 -        // "Manager.getWorkDirPath()+File.separator+getClass().getName()+File.separator+name"
  1.1289 -        int len1 = workDirPath.length();
  1.1290 -        String clazz = caller != null ? caller.getClassName() : "unknown.Class";
  1.1291 -        int len2 = clazz.length();
  1.1292 -        int len3 = name.length();
  1.1293 -        
  1.1294 -        int tooLong = Integer.getInteger("nbjunit.too.long", 100);
  1.1295 -        if (len1 + len2 + len3 > tooLong) {
  1.1296 -            clazz = abbrevDots(clazz);
  1.1297 -            len2 = clazz.length();
  1.1298 -        }
  1.1299 -
  1.1300 -        if (len1 + len2 + len3 > tooLong) {
  1.1301 -            name = abbrevCapitals(name);
  1.1302 -        }
  1.1303 -        
  1.1304 -        String p = workDirPath + File.separator + clazz + File.separator + name;
  1.1305 -        String realP;
  1.1306 -        
  1.1307 -        for (int i = 0; ; i++) {
  1.1308 -            realP = i == 0 ? p : p + "-" + i;
  1.1309 -            if (usedPaths.add(realP)) {
  1.1310 -                break;
  1.1311 -            }
  1.1312 -        }
  1.1313 -        
  1.1314 -        return realP;
  1.1315 -    }
  1.1316 -
  1.1317 -    private static Set<String> usedPaths = new HashSet<String>();
  1.1318 -    
  1.1319 -    private static String abbrevDots(String dotted) {
  1.1320 -        StringBuilder sb = new StringBuilder();
  1.1321 -        String sep = "";
  1.1322 -        for (String item : dotted.split("\\.")) {
  1.1323 -            sb.append(sep);
  1.1324 -            sb.append(item.charAt(0));
  1.1325 -            sep = ".";
  1.1326 -        }
  1.1327 -        return sb.toString();
  1.1328 -    }
  1.1329 -
  1.1330 -    private static String abbrevCapitals(String name) {
  1.1331 -        if (name.startsWith("test")) {
  1.1332 -            name = name.substring(4);
  1.1333 -        }
  1.1334 -        StringBuilder sb = new StringBuilder();
  1.1335 -        for (int i = 0; i < name.length(); i++) {
  1.1336 -            if (Character.isUpperCase(name.charAt(i))) {
  1.1337 -                sb.append(Character.toLowerCase(name.charAt(i)));
  1.1338 -            }
  1.1339 -        }
  1.1340 -        return sb.toString();
  1.1341 -    }
  1.1342 -
  1.1343 -    private static final String JUNIT_PROPERTIES_FILENAME = "junit.properties";
  1.1344 -    private static final String JUNIT_PROPERTIES_LOCATION_PROPERTY = "junit.properties.file";
  1.1345 -    private static final String NBJUNIT_WORKDIR = "nbjunit.workdir";
  1.1346 -    
  1.1347 -    private static String getWorkDirPathFromManager() {
  1.1348 -        String path = System.getProperty(NBJUNIT_WORKDIR);
  1.1349 -                
  1.1350 -        if (path == null) {            
  1.1351 -            // try to get property from user's settings
  1.1352 -            path = readProperties().getProperty(NBJUNIT_WORKDIR);
  1.1353 -        }
  1.1354 -        if (path != null) {
  1.1355 -            path = path.replace('/', File.separatorChar);
  1.1356 -        } else {
  1.1357 -            // Fallback value, guaranteed to be defined.
  1.1358 -            path = System.getProperty("java.io.tmpdir") + File.separatorChar + "tests-" + System.getProperty("user.name");
  1.1359 -        }
  1.1360 -        return path;
  1.1361 -    }
  1.1362 -
  1.1363 -    private static Properties readProperties() {
  1.1364 -        Properties result = new Properties();
  1.1365 -        try {
  1.1366 -            File propFile = getPreferencesFile();
  1.1367 -            FileInputStream is = new FileInputStream(propFile);
  1.1368 -            try {
  1.1369 -                result.load(is);
  1.1370 -            } finally {
  1.1371 -                is.close();
  1.1372 -            }
  1.1373 -        }  catch (IOException e) {
  1.1374 -        }
  1.1375 -        
  1.1376 -        return result;
  1.1377 -    }
  1.1378 -
  1.1379 -    private static File getPreferencesFile() {
  1.1380 -        String junitPropertiesLocation = System.getProperty(JUNIT_PROPERTIES_LOCATION_PROPERTY);
  1.1381 -        if (junitPropertiesLocation != null) {
  1.1382 -            File propertyFile = new File(junitPropertiesLocation);
  1.1383 -            if (propertyFile.exists()) {
  1.1384 -                return propertyFile;
  1.1385 -            }
  1.1386 -        }
  1.1387 -        // property file was not found - lets fall back to defaults
  1.1388 -        String home= System.getProperty("user.home");
  1.1389 -        return new File(home, JUNIT_PROPERTIES_FILENAME);
  1.1390 -    }
  1.1391 -
  1.1392 -    // private method for deleting a file/directory (and all its subdirectories/files)
  1.1393 -    private static void deleteFile(File file) throws IOException {
  1.1394 -        if (file.isDirectory() && file.equals(file.getCanonicalFile())) {
  1.1395 -            // file is a directory - delete sub files first
  1.1396 -            File files[] = file.listFiles();
  1.1397 -            for (int i = 0; i < files.length; i++) {
  1.1398 -                deleteFile(files[i]);
  1.1399 -            }
  1.1400 -            
  1.1401 -        }
  1.1402 -        // file is a File :-)
  1.1403 -        boolean result = file.delete();
  1.1404 -        if (result == false ) {
  1.1405 -            // a problem has appeared
  1.1406 -            throw new IOException("Cannot delete file, file = "+file.getPath());
  1.1407 -        }
  1.1408 -    }
  1.1409 -    
  1.1410 -    // private method for deleting every subfiles/subdirectories of a file object
  1.1411 -    private static void deleteSubFiles(File file) throws IOException {
  1.1412 -        File files[] = file.getCanonicalFile().listFiles();
  1.1413 -        if (files != null) {
  1.1414 -            for (File f : files) {
  1.1415 -                deleteFile(f);
  1.1416 -            }
  1.1417 -        } else {
  1.1418 -            // probably do nothing - file is not a directory
  1.1419 -        }
  1.1420 -    }
  1.1421 -
  1.1422 -    private static FileObject copyStringToFile (FileObject f, String content) throws Exception {
  1.1423 -        OutputStream os = f.getOutputStream();
  1.1424 -        os.write(content.getBytes("UTF-8"));
  1.1425 -        os.close ();
  1.1426 -
  1.1427 -        return f;
  1.1428 -    }
  1.1429 -
  1.1430 -}