Files
NeitzelFXDesigner/designer-kit-ui/src/test/java/de/neitzel/fxdesigner/kit/DiagnosticActionsTest.java
T

113 lines
4.5 KiB
Java

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)));
}
}