001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.java.hints.infrastructure;
042:
043: import java.beans.PropertyVetoException;
044: import java.io.File;
045: import java.io.FileWriter;
046: import java.io.FilenameFilter;
047: import java.io.IOException;
048: import java.io.Writer;
049: import java.net.URL;
050: import java.util.ArrayList;
051: import java.util.Collection;
052: import java.util.Collections;
053: import java.util.Comparator;
054: import java.util.LinkedHashSet;
055: import java.util.LinkedList;
056: import java.util.List;
057: import java.util.concurrent.atomic.AtomicBoolean;
058: import javax.swing.text.Document;
059: import org.netbeans.api.editor.mimelookup.MimePath;
060: import org.netbeans.api.java.lexer.JavaTokenId;
061: import org.netbeans.api.java.source.CancellableTask;
062: import org.netbeans.api.java.source.CompilationInfo;
063: import org.netbeans.api.java.source.JavaSource;
064: import org.netbeans.api.java.source.JavaSource.Phase;
065: import org.netbeans.api.java.source.SourceUtilsTestUtil;
066: import org.netbeans.api.java.source.SourceUtilsTestUtil2;
067: import org.netbeans.api.java.source.gen.WhitespaceIgnoringDiff;
068: import org.netbeans.api.lexer.InputAttributes;
069: import org.netbeans.api.lexer.Language;
070: import org.netbeans.api.lexer.LanguagePath;
071: import org.netbeans.api.lexer.Token;
072: import org.netbeans.api.lexer.TokenId;
073: import org.netbeans.api.progress.ProgressHandle;
074: import org.netbeans.api.progress.ProgressHandleFactory;
075: import org.netbeans.junit.NbTestCase;
076: import org.netbeans.modules.editor.java.JavaKit;
077: import org.netbeans.modules.java.JavaDataLoader;
078: import org.netbeans.modules.java.JavaDataObject.JavaEditorSupport;
079: import org.netbeans.spi.editor.hints.ErrorDescription;
080: import org.netbeans.spi.editor.hints.Fix;
081: import org.netbeans.spi.editor.hints.LazyFixList;
082: import org.openide.cookies.EditorCookie;
083: import org.openide.loaders.DataObject;
084: import org.netbeans.modules.java.source.TestUtil;
085: import org.netbeans.modules.java.source.usages.BinaryAnalyser;
086: import org.netbeans.modules.java.source.usages.ClassIndexImpl;
087: import org.netbeans.modules.java.source.usages.ClassIndexManager;
088: import org.netbeans.modules.java.source.usages.IndexUtil;
089: import org.netbeans.spi.editor.hints.EnhancedFix;
090: import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
091: import org.netbeans.spi.lexer.LanguageEmbedding;
092: import org.netbeans.spi.lexer.LanguageProvider;
093: import org.openide.LifecycleManager;
094: import org.openide.filesystems.FileObject;
095: import org.openide.filesystems.FileUtil;
096: import org.openide.filesystems.LocalFileSystem;
097: import org.openide.filesystems.Repository;
098: import org.openide.filesystems.URLMapper;
099: import org.openide.util.Lookup;
100: import org.openide.util.lookup.Lookups;
101:
102: /**
103: * @author Jan Lahoda
104: */
105: public class HintsTestBase extends NbTestCase {
106:
107: /** Need to be defined because of JUnit */
108: public HintsTestBase(String name) {
109: super (name);
110:
111: }
112:
113: private FileObject packageRoot;
114: private FileObject testSource;
115: private JavaSource js;
116: protected CompilationInfo info;
117:
118: private static File cache;
119: private static FileObject cacheFO;
120:
121: private CancellableTask<CompilationInfo> task;
122:
123: protected void setUp() throws Exception {
124: doSetUp(layer());
125: }
126:
127: protected void doSetUp(String resource) throws Exception {
128: SourceUtilsTestUtil.prepareTest(new String[] {
129: "org/netbeans/modules/java/editor/resources/layer.xml",
130: resource }, new Object[] { JavaDataLoader.class,
131: new MimeDataProvider() {
132: public Lookup getLookup(MimePath mimePath) {
133: return Lookups
134: .fixed(new Object[] { new JavaKit(), });
135: }
136: }, new LanguageProvider() {
137: public Language<?> findLanguage(String mimePath) {
138: return JavaTokenId.language();
139: }
140:
141: public LanguageEmbedding<?> findLanguageEmbedding(
142: Token<?> token, LanguagePath languagePath,
143: InputAttributes inputAttributes) {
144: return null;
145: }
146: } });
147:
148: if (cache == null) {
149: cache = FileUtil.normalizeFile(TestUtil.createWorkFolder());
150: cacheFO = FileUtil.toFileObject(cache);
151:
152: cache.deleteOnExit();
153:
154: IndexUtil.setCacheFolder(cache);
155:
156: if (createCaches()) {
157: for (URL u : SourceUtilsTestUtil.getBootClassPath()) {
158: FileObject file = URLMapper.findFileObject(u);
159:
160: if (file == null)
161: continue;
162:
163: file = FileUtil.getArchiveFile(file);
164:
165: if (file == null)
166: continue;
167:
168: File jioFile = FileUtil.toFile(file);
169:
170: if (jioFile == null)
171: continue;
172:
173: final ClassIndexImpl ci = ClassIndexManager
174: .getDefault().createUsagesQuery(u, false);
175: ProgressHandle handle = ProgressHandleFactory
176: .createHandle("cache creation");
177: BinaryAnalyser ba = ci.getBinaryAnalyser();
178:
179: ba.start(u, handle, new AtomicBoolean(false),
180: new AtomicBoolean(false));
181: ba.finish();
182: }
183: }
184: }
185: }
186:
187: protected boolean createCaches() {
188: return true;
189: }
190:
191: protected String testDataExtension() {
192: return "org/netbeans/test/java/hints/";
193: }
194:
195: protected String layer() {
196: return "org/netbeans/modules/java/hints/resources/layer.xml";
197: }
198:
199: protected void prepareTest(String capitalizedName) throws Exception {
200: FileObject workFO = makeScratchDir(this );
201:
202: assertNotNull(workFO);
203:
204: FileObject sourceRoot = workFO.createFolder("src");
205: FileObject buildRoot = workFO.createFolder("build");
206: // FileObject cache = workFO.createFolder("cache");
207:
208: packageRoot = FileUtil.createFolder(sourceRoot,
209: testDataExtension());
210:
211: SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cacheFO);
212:
213: String testPackagePath = testDataExtension();
214: File testPackageFile = new File(getDataDir(), testPackagePath);
215:
216: String[] names = testPackageFile.list(new FilenameFilter() {
217: public boolean accept(File dir, String name) {
218: if (name.endsWith(".java"))
219: return true;
220:
221: return false;
222: }
223: });
224:
225: String[] files = new String[names.length];
226:
227: for (int cntr = 0; cntr < files.length; cntr++) {
228: files[cntr] = testPackagePath + names[cntr];
229: }
230:
231: TestUtil.copyFiles(getDataDir(), FileUtil.toFile(sourceRoot),
232: files);
233:
234: packageRoot.refresh();
235:
236: capitalizedName = capitalizedName.substring(capitalizedName
237: .lastIndexOf('.') + 1);
238:
239: testSource = packageRoot.getFileObject(capitalizedName
240: + ".java");
241:
242: assertNotNull(testSource);
243:
244: js = JavaSource.forFileObject(testSource);
245:
246: assertNotNull(js);
247:
248: info = SourceUtilsTestUtil.getCompilationInfo(js,
249: Phase.RESOLVED);
250:
251: assertNotNull(info);
252:
253: task = new LazyHintComputationFactory().createTask(testSource);
254: }
255:
256: /**Copied from org.netbeans.api.project.
257: * Create a scratch directory for tests.
258: * Will be in /tmp or whatever, and will be empty.
259: * If you just need a java.io.File use clearWorkDir + getWorkDir.
260: */
261: public static FileObject makeScratchDir(NbTestCase test)
262: throws IOException {
263: test.clearWorkDir();
264: File root = test.getWorkDir();
265: assert root.isDirectory() && root.list().length == 0;
266:
267: FileUtil.refreshFor(File.listRoots());
268:
269: FileObject fo = FileUtil.toFileObject(root);
270: if (fo != null) {
271: // Presumably using masterfs.
272: return fo;
273: } else {
274: // For the benefit of those not using masterfs.
275: LocalFileSystem lfs = new LocalFileSystem();
276: try {
277: lfs.setRootDirectory(root);
278: } catch (PropertyVetoException e) {
279: assert false : e;
280: }
281: Repository.getDefault().addFileSystem(lfs);
282: return lfs.getRoot();
283: }
284: }
285:
286: // private int getOffset(Document doc, int linenumber, int column) {
287: // return NbDocument.findLineOffset((StyledDocument) doc, linenumber - 1) + column - 1;
288: // }
289:
290: private List<Fix> getFixes(ErrorDescription d) throws Exception {
291: LazyFixList f = d.getFixes();
292:
293: f.getFixes();
294:
295: task.run(info);
296:
297: return f.getFixes();
298: }
299:
300: //XXX: copied from org.netbeans.modules.editor.hints.borrowed.ListCompletionView, would be nice to have this on one place only:
301: private List<Fix> sortFixes(Collection<Fix> fixes) {
302: fixes = new LinkedHashSet<Fix>(fixes);
303:
304: List<EnhancedFix> sortableFixes = new ArrayList<EnhancedFix>();
305: List<Fix> other = new LinkedList<Fix>();
306:
307: for (Fix f : fixes) {
308: if (f instanceof EnhancedFix) {
309: sortableFixes.add((EnhancedFix) f);
310: } else {
311: other.add(f);
312: }
313: }
314:
315: Collections.sort(sortableFixes, new FixComparator());
316:
317: List<Fix> result = new ArrayList<Fix>();
318:
319: result.addAll(sortableFixes);
320: result.addAll(other);
321:
322: return result;
323: }
324:
325: private static final class FixComparator implements
326: Comparator<EnhancedFix> {
327:
328: public int compare(EnhancedFix o1, EnhancedFix o2) {
329: return compareText(o1.getSortText(), o2.getSortText());
330: }
331:
332: }
333:
334: private static int compareText(CharSequence text1,
335: CharSequence text2) {
336: int len = Math.min(text1.length(), text2.length());
337: for (int i = 0; i < len; i++) {
338: char ch1 = text1.charAt(i);
339: char ch2 = text2.charAt(i);
340: if (ch1 != ch2) {
341: return ch1 - ch2;
342: }
343: }
344: return text1.length() - text2.length();
345: }
346:
347: private int getStartLine(ErrorDescription d) throws IOException {
348: return d.getRange().getBegin().getLine();
349: }
350:
351: protected void performHintsPresentCheck(String className, int line,
352: int column, boolean present) throws Exception {
353: prepareTest(className);
354: DataObject od = DataObject.find(testSource);
355: EditorCookie ec = od.getCookie(EditorCookie.class);
356:
357: Document doc = ec.openDocument();
358:
359: List<ErrorDescription> errors = new ErrorHintsProvider(
360: testSource).computeErrors(info, doc);
361: List<Fix> fixes = new ArrayList<Fix>();
362:
363: for (ErrorDescription d : errors) {
364: if (getStartLine(d) + 1 == line)
365: fixes.addAll(getFixes(d));
366: }
367:
368: if (present) {
369: assertTrue(fixes != null && !fixes.isEmpty());
370: } else {
371: assertTrue(fixes == null || fixes.isEmpty());
372: }
373: }
374:
375: protected void performTestDoNotPerform(String className, int line,
376: int column) throws Exception {
377: prepareTest(className);
378: DataObject od = DataObject.find(testSource);
379: EditorCookie ec = od.getCookie(EditorCookie.class);
380:
381: Document doc = ec.openDocument();
382:
383: List<ErrorDescription> errors = new ErrorHintsProvider(
384: testSource).computeErrors(info, doc);
385: List<Fix> fixes = new ArrayList<Fix>();
386:
387: for (ErrorDescription d : errors) {
388: if (getStartLine(d) + 1 == line)
389: fixes.addAll(getFixes(d));
390: }
391:
392: fixes = sortFixes(fixes);
393:
394: File fixesDump = new File(getWorkDir(), getName()
395: + "-hints.out");
396: File diff = new File(getWorkDir(), getName() + "-hints.diff");
397:
398: Writer hintsWriter = new FileWriter(fixesDump);
399:
400: for (Fix f : fixes) {
401: hintsWriter.write(f.getText());
402: hintsWriter.write("\n");
403: }
404:
405: hintsWriter.close();
406:
407: File hintsGolden = getGoldenFile(getName() + "-hints.pass");
408:
409: assertFile(fixesDump, hintsGolden, diff);
410: }
411:
412: protected void performTest(String className, String performHint,
413: int line, int column) throws Exception {
414: performTest(className, className, performHint, line, column,
415: true);
416: }
417:
418: protected void performTest(String className,
419: String modifiedClassName, String performHint, int line,
420: int column, boolean checkHintList) throws Exception {
421: prepareTest(className);
422: DataObject od = DataObject.find(testSource);
423: EditorCookie ec = od.getCookie(EditorCookie.class);
424:
425: try {
426: Document doc = ec.openDocument();
427:
428: List<ErrorDescription> errors = new ErrorHintsProvider(
429: testSource).computeErrors(info, doc);
430: List<Fix> fixes = new ArrayList<Fix>();
431:
432: for (ErrorDescription d : errors) {
433: if (getStartLine(d) + 1 == line)
434: fixes.addAll(getFixes(d));
435: }
436:
437: fixes = sortFixes(fixes);
438:
439: Fix toPerform = null;
440:
441: if (checkHintList) {
442: File fixesDump = new File(getWorkDir(), getName()
443: + "-hints.out");
444:
445: Writer hintsWriter = new FileWriter(fixesDump);
446:
447: for (Fix f : fixes) {
448: if (f.getText().indexOf(performHint) != (-1)) {
449: toPerform = f;
450: }
451:
452: hintsWriter.write(f.getText());
453: hintsWriter.write("\n");
454: }
455:
456: hintsWriter.close();
457:
458: File hintsGolden = getGoldenFile(getName()
459: + "-hints.pass");
460: File diff = new File(getWorkDir(), getName()
461: + "-hints.diff");
462:
463: assertFile(fixesDump, hintsGolden, diff);
464: } else {
465: for (Fix f : fixes) {
466: if (f.getText().indexOf(performHint) != (-1)) {
467: toPerform = f;
468: }
469: }
470: }
471:
472: assertNotNull(toPerform);
473:
474: toPerform.implement();
475:
476: File dump = new File(getWorkDir(), getName() + ".out");
477:
478: Writer writer = new FileWriter(dump);
479:
480: Document modifDoc;
481: if (className.equals(modifiedClassName)) {
482: modifDoc = doc;
483: } else {
484: FileObject modFile = packageRoot
485: .getFileObject(modifiedClassName + ".java");
486: od = DataObject.find(modFile);
487: ec = od.getCookie(EditorCookie.class);
488: modifDoc = ec.openDocument();
489: }
490:
491: writer.write(modifDoc.getText(0, modifDoc.getLength()));
492:
493: writer.close();
494:
495: File golden = getGoldenFile();
496:
497: assertNotNull(golden);
498:
499: File diff = new File(getWorkDir(), getName() + ".diff");
500:
501: assertFile(dump, golden, diff, new WhitespaceIgnoringDiff());
502: } finally {
503: SourceUtilsTestUtil2.ignoreCompileRequests();
504: LifecycleManager.getDefault().saveAll();
505: }
506: }
507:
508: }
|