blob: 3d4345aaf3db5d56b2148e1b852d33866ed79340 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.editor.hints;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.Position;
import org.netbeans.api.editor.mimelookup.MimePath;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.GuardedDocument;
import org.netbeans.editor.Utilities;
import org.netbeans.junit.MockServices;
import org.netbeans.junit.NbTestCase;
import org.netbeans.spi.editor.highlighting.HighlightsSequence;
import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
import org.netbeans.spi.editor.hints.Severity;
import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
import org.openide.LifecycleManager;
import org.openide.cookies.EditorCookie;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import static org.netbeans.modules.editor.hints.AnnotationHolder.*;
import org.netbeans.spi.editor.hints.Fix;
import static org.netbeans.spi.editor.hints.Severity.*;
/**
*
* @author Jan Lahoda
*/
public class AnnotationHolderTest extends NbTestCase {
private FileObject file;
private Document doc;
private EditorCookie ec;
/** Creates a new instance of AnnotationHolderTest */
public AnnotationHolderTest(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
MockServices.setServices(MimeDataProviderImpl.class);
FileSystem fs = FileUtil.createMemoryFileSystem();
file = fs.getRoot().createData("test.txt");
writeIntoFile(file, "01234567890123456789\n abcdefg \n hijklmnop");
DataObject od = DataObject.find(file);
ec = od.getCookie(EditorCookie.class);
doc = ec.openDocument();
}
public void testMultiLineErrors() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(null, Severity.ERROR, "clank-diagnostics-error", "1", null,
ErrorDescriptionFactory.lazyListForFixes(Collections.<Fix>emptyList()), file, new int[] {33 - 30, 55 - 30 - 1},
new int[] {40 - 30, 58 - 30 -1});
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(null, Severity.WARNING, "clank-diagnostics-warning", "1", null,
ErrorDescriptionFactory.lazyListForFixes(Collections.<Fix>emptyList()), file, new int[] {55 - 30 - 1, 69 - 30 - 2},
new int[] {58 - 30 - 1, 75 - 30 - 2});
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {33 - 30, 40 - 30, 55 - 30 - 1, 58 - 30 - 1, 69 - 30 -2, 75 - 30 - 2},
new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc),
AnnotationHolder.getColoring(ERROR, doc),
AnnotationHolder.getColoring(WARNING, doc)});
}
public void testComputeHighlightsOneLayer1() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 1, 3);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "2", file, 5, 6);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, 3, 5, 6}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc), AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeHighlightsOneLayer2() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 1, 7);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "2", file, 5, 6);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, 7}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeHighlightsOneLayer3() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 1, 5);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "2", file, 3, 7);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, 7}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeHighlightsOneLayer4() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 3, 5);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "2", file, 1, 7);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, 7}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeHighlightsTwoLayers1() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 1, 3);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 5, 7);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, 3, 5, 7}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc), AnnotationHolder.getColoring(WARNING, doc)});
}
public void testComputeHighlightsTwoLayers2() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 1, 7);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 3, 5);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, 7}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeHighlightsTwoLayers3() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 3, 5);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 4, 7);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {3, 5, /*6*/5, 7}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc), AnnotationHolder.getColoring(WARNING, doc)});
}
public void testComputeHighlightsTwoLayers4() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 3, 5);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 1, 4);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, /*2*/3, 3, 5}, new AttributeSet[] {AnnotationHolder.getColoring(WARNING, doc), AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeHighlightsTwoLayers5() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 3, 5);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 1, 7);
List<ErrorDescription> errors = Arrays.asList(ed1, ed2);
final OffsetsBag bag = AnnotationHolder.computeHighlights(doc, errors);
assertHighlights("",bag, new int[] {1, /*2*/3, 3, 5, /*6*/5, 7}, new AttributeSet[] {AnnotationHolder.getColoring(WARNING, doc), AnnotationHolder.getColoring(ERROR, doc), AnnotationHolder.getColoring(WARNING, doc)});
}
public void testNullSpan() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 3, 5);
ErrorDescription ed3 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 1, 7);
ec.open();
AnnotationHolder.getInstance(file).setErrorDescriptions("foo", Arrays.asList(ed1, ed3));
ec.close();
}
public void testMultilineHighlights() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 47 - 30, 72 - 30);
OffsetsBag bag = new OffsetsBag(doc);
List<ErrorDescription> errors = Arrays.asList(ed1);
BaseDocument bdoc = (BaseDocument) doc;
bag = new OffsetsBag(doc);
AnnotationHolder.updateHighlightsOnLine(bag, bdoc, bdoc.createPosition(Utilities.getRowStartFromLineOffset(bdoc, 0)), errors);
assertHighlights("", bag, new int[] {47 - 30, 50 - 30}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
bag = new OffsetsBag(doc);
AnnotationHolder.updateHighlightsOnLine(bag, bdoc, bdoc.createPosition(Utilities.getRowStartFromLineOffset(bdoc, 1)), errors);
assertHighlights("", bag, new int[] {53 - 30, 60 - 30}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
bag = new OffsetsBag(doc);
AnnotationHolder.updateHighlightsOnLine(bag, bdoc, bdoc.createPosition(Utilities.getRowStartFromLineOffset(bdoc, 2)), errors);
assertHighlights("", bag, new int[] {65 - 30, 72 - 30}, new AttributeSet[] {AnnotationHolder.getColoring(ERROR, doc)});
}
public void testComputeSeverity() throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 3, 5);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.HINT, "2", file, 1, 7);
ErrorDescription ed3 = ErrorDescriptionFactory.createErrorDescription(Severity.WARNING, "2", file, 1, 7);
ErrorDescription ed4 = ErrorDescriptionFactory.createErrorDescription(Severity.VERIFIER, "2", file, 1, 7);
ec.open();
class AttacherImpl implements Attacher {
private ParseErrorAnnotation annotation;
public void attachAnnotation(Position line, ParseErrorAnnotation a, boolean synchronous) throws BadLocationException {
if (line.getOffset() == 0) {
this.annotation = a;
}
}
public void detachAnnotation(ParseErrorAnnotation a, boolean synchronous) {}
}
AttacherImpl impl = new AttacherImpl();
AnnotationHolder.getInstance(file).attacher = impl;
AnnotationHolder.getInstance(file).setErrorDescriptions("foo", Arrays.asList(ed1, ed2, ed3));
assertEquals(Severity.ERROR, impl.annotation.getSeverity());
AnnotationHolder.getInstance(file).setErrorDescriptions("foo", Arrays.asList(ed2, ed3));
assertEquals(Severity.WARNING, impl.annotation.getSeverity());
AnnotationHolder.getInstance(file).setErrorDescriptions("foo", Arrays.asList(ed2));
assertEquals(Severity.HINT, impl.annotation.getSeverity());
AnnotationHolder.getInstance(file).setErrorDescriptions("foo", Arrays.asList(ed2, ed4));
assertEquals(Severity.VERIFIER, impl.annotation.getSeverity());
ec.close();
}
public void testTypeIntoLine() throws Exception {
performTypingTest(25, "a", new int[0]);
}
public void testTypeOnLineStart() throws Exception {
performTypingTest(21, "a", new int[0]);
}
public void testTypeOnLineStartWithNewline() throws Exception {
performTypingTest(21, "a\n", new int[0]);
}
public void testTypeOnLineStartWithNewlines() throws Exception {
performTypingTest(21, "a\na\na\na\n", new int[0]);
}
public void testTypeNewline() throws Exception {
performTypingTest(22, "asdasd\nasdfasdf", new int[] {23, 25}, new int[0]);
}
public void testType190393a() throws Exception {
doc.remove(0, doc.getLength());
doc.insertString(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne", null);
performTypingTest(5, "x", new int[] {8, 9}, new int[] {9, 10});
}
public void testType190393b() throws Exception {
doc.remove(0, doc.getLength());
doc.insertString(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne", null);
performTypingTest(4, 1, "", new int[] {8, 9}, new int[] {7, 8});
}
public void test205675() throws Exception {
doc.remove(0, doc.getLength());
doc.insertString(0, "a\nb\nc\nd\ne\n", null);
ErrorDescription ed0 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "0", file, 0, 1);
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, 2, 3);
ErrorDescription ed2 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "2", file, 4, 5);
AnnotationHolder ah = AnnotationHolder.getInstance(file);
ah.setErrorDescriptions("test", Arrays.asList(ed0, ed1, ed2));
assertEquals(Arrays.asList(ed0), ah.getErrorsGE(0));
assertEquals(Arrays.asList(ed1), ah.getErrorsGE(1));
assertEquals(Arrays.asList(ed1), ah.getErrorsGE(2));
assertEquals(Arrays.asList(ed2), ah.getErrorsGE(3));
assertEquals(Arrays.asList(ed2), ah.getErrorsGE(4));
assertEquals(Arrays.asList(), ah.getErrorsGE(5));
}
private void performTypingTest(int index, String insertWhat, int[] highlightSpans) throws Exception {
performTypingTest(index, insertWhat, new int[] {21, 32}, highlightSpans);
}
private void performTypingTest(int index, String insertWhat, int[] errorSpan, int[] highlightSpans) throws Exception {
performTypingTest(index, 0, insertWhat, errorSpan, highlightSpans);
}
private void performTypingTest(int index, int remove, String insertWhat, int[] errorSpan, int[] highlightSpans) throws Exception {
ErrorDescription ed1 = ErrorDescriptionFactory.createErrorDescription(Severity.ERROR, "1", file, errorSpan[0], errorSpan[1]);
ec.open();
//these tests currently ignore annotations:
class AttacherImpl implements Attacher {
public void attachAnnotation(Position line, ParseErrorAnnotation a, boolean synchronous) throws BadLocationException {}
public void detachAnnotation(ParseErrorAnnotation a, boolean synchronous) {}
}
AnnotationHolder.getInstance(file).attacher = new AttacherImpl();
AnnotationHolder.getInstance(file).setErrorDescriptions("foo", Arrays.asList(ed1));
doc.remove(index, remove);
doc.insertString(index, insertWhat, null);
assertHighlights("highlights correct", AnnotationHolder.getBag(doc), highlightSpans, null);
LifecycleManager.getDefault().saveAll();
ec.close();
}
private void assertHighlights(String message, OffsetsBag bag, int[] spans, AttributeSet[] values) {
HighlightsSequence hs = bag.getHighlights(0, Integer.MAX_VALUE);
int index = 0;
while (hs.moveNext()) {
assertEquals(message, spans[2 * index], hs.getStartOffset());
assertEquals(message, spans[2 * index + 1], hs.getEndOffset());
if (values != null) {
assertEquals(message, values[index], hs.getAttributes());
}
index++;
}
assertEquals(2 * index, spans.length);
}
@Override
protected boolean runInEQ() {
return true;
}
private void writeIntoFile(FileObject file, String what) throws Exception {
FileLock lock = file.lock();
OutputStream out = file.getOutputStream(lock);
try {
out.write(what.getBytes());
} finally {
out.close();
lock.releaseLock();
}
}
public static final class MimeDataProviderImpl implements MimeDataProvider {
@SuppressWarnings("deprecation")
public Lookup getLookup(MimePath mimePath) {
return Lookups.singleton(new DefaultEditorKit() {
@Override
public Document createDefaultDocument() {
return new GuardedDocument(this.getClass());
}
});
}
}
}