Add source highlighting and revision-checked diagnostic fixes in both hosts
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package de.neitzel.fxdesigner.kit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import de.neitzel.fxdesigner.contracts.*;
|
||||
import de.neitzel.fxdesigner.host.HostServices.*;
|
||||
import de.neitzel.fxdesigner.protocol.BindingMetadata.Problem;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DiagnosticActionsTest {
|
||||
private static final String XML =
|
||||
"<?neitzel-model app.Person?>\r\n"
|
||||
+ "<?import de.neitzel.fx.view.*?><VBox"
|
||||
+ " xmlns:fx='http://javafx.com/fxml/1'><fx:define><BindingList><!-- before"
|
||||
+ " --><DirectBinding control='name' property='text' path='name' direction = 'bad'"
|
||||
+ " extra='keep'/><!-- after --></BindingList></fx:define><Label fx:id='name'"
|
||||
+ " text='bad'/></VBox>";
|
||||
|
||||
private DocumentSnapshot snapshot(String text, boolean writable) {
|
||||
return new DocumentSnapshot(URI.create("file:/View.fxml"), 7, text, writable, true);
|
||||
}
|
||||
|
||||
private Diagnostic direction(DocumentSnapshot d) {
|
||||
return FxmlDiagnostics.local(d).stream()
|
||||
.filter(p -> p.message().startsWith("Invalid or missing direction:"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
private String apply(DocumentSnapshot d, QuickFix fix) {
|
||||
return new EditBatch(d.revision(), fix.label(), fix.edits()).applyTo(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void directionChoicesAreExplicitAndChangeOnlyTheAttributeValue() {
|
||||
var d = snapshot(XML, true);
|
||||
var problem = direction(d);
|
||||
assertEquals(
|
||||
"bad",
|
||||
XML.substring(problem.range().orElseThrow().start(), problem.range().orElseThrow().end()));
|
||||
assertEquals(3, problem.fixes().size());
|
||||
for (var fix : problem.fixes()) {
|
||||
String value = fix.label().substring(fix.label().lastIndexOf(' ') + 1);
|
||||
assertEquals(XML.replace("direction = 'bad'", "direction = '" + value + "'"), apply(d, fix));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingAndEmptyDirectionKeepSourceAndHighlightAnActualRange() {
|
||||
for (String text :
|
||||
List.of(XML.replace(" direction = 'bad'", ""), XML.replace("'bad' extra", "'' extra"))) {
|
||||
var d = snapshot(text, true);
|
||||
var p = direction(d);
|
||||
assertTrue(p.range().orElseThrow().end() > p.range().orElseThrow().start());
|
||||
String fixed = apply(d, p.fixes().getFirst());
|
||||
assertTrue(fixed.contains("<!-- before -->"));
|
||||
assertTrue(fixed.contains("extra='keep'"));
|
||||
assertFalse(
|
||||
FxmlDiagnostics.local(snapshot(fixed, true)).stream()
|
||||
.anyMatch(x -> x.message().startsWith("Invalid or missing direction:")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void duplicateRemovalPreservesFirstDeclarationAndSurroundingComments() {
|
||||
String declaration = "<ComputedBinding control='name' property='text' method='#name'/>";
|
||||
String text =
|
||||
XML.replace("'bad' extra", "'view' extra")
|
||||
.replace("<!-- after -->", "<!-- after -->" + declaration + "<!-- end -->");
|
||||
var d = snapshot(text, true);
|
||||
var p =
|
||||
FxmlDiagnostics.local(d).stream()
|
||||
.filter(x -> x.message().startsWith("Duplicate binding target:"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
assertEquals(text.replace(declaration, ""), apply(d, p.fixes().getFirst()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetFixesRequireKnownSimpleDeclarationsAndNeverRemoveControls() {
|
||||
var p = new Problem("name", "text", "ERROR", "unknown path");
|
||||
var d = snapshot(XML, true);
|
||||
assertEquals(1, FxmlDiagnostics.target(d, List.of(p)).getFirst().fixes().size());
|
||||
for (String text :
|
||||
List.of(
|
||||
XML.replace("extra='keep'", "fx:id='binding'"),
|
||||
XML.replace(
|
||||
"extra='keep'/>", "extra='keep'><converter>app.C</converter></DirectBinding>"),
|
||||
XML.replace("DirectBinding", "app.UnknownBinding")))
|
||||
assertTrue(
|
||||
FxmlDiagnostics.target(snapshot(text, true), List.of(p)).getFirst().fixes().isEmpty());
|
||||
assertTrue(
|
||||
FxmlDiagnostics.target(d, List.of(new Problem("name", "text", "WARNING", "unverified")))
|
||||
.getFirst()
|
||||
.fixes()
|
||||
.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void readOnlyAndStaleSourceCannotApplyFixes() {
|
||||
assertTrue(direction(snapshot(XML, false)).fixes().isEmpty());
|
||||
var d = snapshot(XML, true);
|
||||
var fix = direction(d).fixes().getFirst();
|
||||
var edit = new EditBatch(d.revision(), fix.label(), fix.edits());
|
||||
assertThrows(
|
||||
ConcurrentModificationException.class,
|
||||
() -> edit.applyTo(new DocumentSnapshot(d.document(), 8, XML, true, true)));
|
||||
assertThrows(IllegalStateException.class, () -> edit.applyTo(snapshot(XML, false)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user