sandbox/java.hints/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java
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("<input Java source code>")
1.170 - * .run(<class containg the hint>)
1.171 - * .assertWarnings("<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("<input Java source code>")
1.181 - * .run(<class containg the hint>)
1.182 - * .findWarning("<a warning produce by the hint>")
1.183 - * .applyFix() //fill apply the only fix in the given ErrorDescription
1.184 - * .assertCompilable()
1.185 - * .assertOutput("<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 -}