Files
NeitzelFXDesigner/integration-tests/idea/WorkflowProbe.java
T

283 lines
12 KiB
Java

package qualification;
import com.intellij.openapi.application.*;
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.vfs.*;
import com.oracle.javafx.scenebuilder.kit.fxom.*;
import de.neitzel.fxdesigner.kit.*;
import java.nio.file.*;
import java.util.concurrent.*;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.control.Button;
/** Disposable companion plugin, never included in the delivered designer plugin. */
public final class WorkflowProbe implements StartupActivity.DumbAware {
static final Path output = Path.of(System.getProperty("designer.check.output"));
static DesignerPane active;
static final java.util.concurrent.atomic.AtomicBoolean started =
new java.util.concurrent.atomic.AtomicBoolean();
static <T> T edt(Callable<T> action) throws Exception {
var f = new CompletableFuture<T>();
ApplicationManager.getApplication()
.invokeLater(
() ->
WriteIntentReadAction.run(
() -> {
try {
f.complete(action.call());
} catch (Throwable t) {
f.completeExceptionally(t);
}
}),
ModalityState.nonModal());
return f.get(20, TimeUnit.SECONDS);
}
static <T> T fx(Callable<T> action) throws Exception {
var f = new CompletableFuture<T>();
Platform.runLater(
() -> {
try {
f.complete(action.call());
} catch (Throwable t) {
f.completeExceptionally(t);
}
});
return f.get(20, TimeUnit.SECONDS);
}
static JFXPanel bridge(java.awt.Component c) {
if (c instanceof JFXPanel p) return p;
if (c instanceof java.awt.Container parent)
for (var child : parent.getComponents()) {
var p = bridge(child);
if (p != null) return p;
}
return null;
}
static void await(Callable<Boolean> condition) throws Exception {
long until = System.nanoTime() + TimeUnit.SECONDS.toNanos(120);
while (System.nanoTime() < until) {
if (condition.call()) return;
Thread.sleep(100);
}
throw new AssertionError("IDE workflow timed out");
}
static void click(DesignerPane pane, String text) throws Exception {
fx(
() -> {
((Button)
pane.lookupAll(".button").stream()
.filter(n -> n instanceof Button b && b.getText().equals(text))
.findFirst()
.orElseThrow())
.fire();
return null;
});
}
public void runActivity(Project project) {
if (!started.compareAndSet(false, true)) return;
ApplicationManager.getApplication()
.executeOnPooledThread(
() -> {
try {
Path path =
Path.of(
project.getBasePath(),
"app/src/main/resources/fixture/components/Person.fxml");
VirtualFile file =
edt(() -> LocalFileSystem.getInstance().refreshAndFindFileByNioFile(path));
FileEditor editor =
edt(
() -> {
var manager = FileEditorManager.getInstance(project);
var all = manager.openFile(file, true);
manager.setSelectedEditor(file, "neitzel-fx-designer");
return java.util.Arrays.stream(all)
.filter(e -> e.getName().equals("Neitzel Designer"))
.findFirst()
.orElseThrow();
});
await(() -> edt(() -> bridge(editor.getComponent()) != null));
JFXPanel bridge = edt(() -> bridge(editor.getComponent()));
await(
() ->
fx(
() ->
bridge.getScene() != null
&& bridge.getScene().getRoot() instanceof DesignerPane));
DesignerPane pane = fx(() -> (DesignerPane) bridge.getScene().getRoot());
active = pane;
await(() -> fx(() -> pane.kit().editor().getFxomDocument() != null));
click(pane, "Build and Refresh");
await(
() ->
fx(
() ->
java.util.List.of("card", "second").stream()
.allMatch(
id -> {
var item =
new FXOMFxIdIndex(
pane.kit().editor().getFxomDocument())
.lookup(id);
return item instanceof FXOMInstance instance
&& instance.getSceneGraphObject()
instanceof SnapshotRegion region
&& region.image() != null
&& region.statusText().equals("Target runtime");
})));
fx(
() -> {
var kit = pane.kit().editor();
var card =
(FXOMInstance) new FXOMFxIdIndex(kit.getFxomDocument()).lookup("card");
kit.getSelection().select(card);
var property =
(FXOMPropertyT)
card.getProperties()
.get(
new com.oracle.javafx.scenebuilder.kit.metadata.util
.PropertyName("caption"));
String old = property.getValue();
kit.getJobManager()
.push(
new com.oracle.javafx.scenebuilder.kit.editor.job.Job(kit) {
public boolean isExecutable() {
return true;
}
public String getDescription() {
return "IDE caption check";
}
public void execute() {
set("IDE canvas draft");
}
public void undo() {
set(old);
}
public void redo() {
execute();
}
void set(String text) {
var doc = kit.getFxomDocument();
doc.beginUpdate();
try {
property.setValue(text);
} finally {
doc.endUpdate();
}
}
});
return null;
});
await(
() ->
edt(
() ->
FileDocumentManager.getInstance()
.getDocument(file)
.getText()
.contains("IDE canvas draft")));
click(pane, "Undo");
await(
() ->
edt(
() ->
FileDocumentManager.getInstance()
.getDocument(file)
.getText()
.contains("FXML caption")));
click(pane, "Redo");
await(
() ->
edt(
() ->
FileDocumentManager.getInstance()
.getDocument(file)
.getText()
.contains("IDE canvas draft")));
click(pane, "Render drafts");
await(
() ->
fx(
() ->
java.util.List.of("card", "second").stream()
.allMatch(
id -> {
var item =
new FXOMFxIdIndex(
pane.kit().editor().getFxomDocument())
.lookup(id);
return item instanceof FXOMInstance instance
&& instance.getSceneGraphObject()
instanceof SnapshotRegion region
&& region.image() != null
&& region.statusText().equals("Target runtime");
})));
fx(
() -> {
javax.imageio.ImageIO.write(
javafx.embed.swing.SwingFXUtils.fromFXImage(
pane.snapshot(null, null), null),
"png",
output.resolve("intellij.png").toFile());
return null;
});
try (var document =
pane.kit().host().documents().open(path.toUri()).toCompletableFuture().get()) {
de.neitzel.fxdesigner.kit.ProjectionHostChecks.run(pane, document);
}
String version = fx(() -> System.getProperty("javafx.runtime.version"));
if (!version.startsWith("26"))
throw new AssertionError("Wrong host JavaFX: " + version);
Files.writeString(
output.resolve("SUCCESS.txt"),
"PASS registered IntelliJ editor, shared Kit, real Build and Refresh, target"
+ " pixels, native document edits, undo/redo, draft render,"
+ " source-preserving projection and extended Component scenarios; JavaFX "
+ version
+ "\n");
} catch (Throwable e) {
try {
if (active != null)
fx(
() -> {
Files.writeString(
output.resolve("ui-state.txt"),
active.lookupAll(".label").stream()
.filter(n -> n instanceof javafx.scene.control.Label)
.map(
n ->
String.valueOf(
((javafx.scene.control.Label) n).getText()))
.toList()
.toString());
javax.imageio.ImageIO.write(
javafx.embed.swing.SwingFXUtils.fromFXImage(
active.snapshot(null, null), null),
"png",
output.resolve("failed.png").toFile());
return null;
});
var w = new java.io.StringWriter();
e.printStackTrace(new java.io.PrintWriter(w));
Files.writeString(output.resolve("FAILURE.txt"), w.toString());
} catch (Exception ignored) {
}
}
});
}
}