Files

263 lines
12 KiB
Java

package qualification;
import com.oracle.javafx.scenebuilder.kit.fxom.*;
import de.neitzel.fxdesigner.contracts.*;
import de.neitzel.fxdesigner.host.*;
import de.neitzel.fxdesigner.kit.*;
import de.neitzel.fxdesigner.workflow.*;
import java.lang.instrument.Instrumentation;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import javafx.application.Platform;
import javafx.scene.control.Button;
import javafx.stage.*;
/** External probe for the actual library example, never shipped in a host or application. */
public final class FxExampleProbe {
static <T> T fx(Callable<T> action) throws Exception {
var answer = new CompletableFuture<T>();
Platform.runLater(
() -> {
try {
answer.complete(action.call());
} catch (Throwable e) {
answer.completeExceptionally(e);
}
});
return answer.get(20, TimeUnit.SECONDS);
}
static void await(Callable<Boolean> condition) throws Exception {
long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(150);
while (System.nanoTime() < end) {
if (condition.call()) return;
Thread.sleep(100);
}
throw new AssertionError("fx-example condition timed out");
}
static void check(boolean condition, String message) {
if (!condition) throw new AssertionError(message);
}
public static void premain(String arg, Instrumentation ignored) {
Thread.ofPlatform()
.daemon()
.start(
() -> {
Path output = Path.of(System.getProperty("example.output")),
library = Path.of(System.getProperty("example.library"));
try {
for (int i = 0; i < 200; i++) {
try {
fx(() -> null);
break;
} catch (IllegalStateException notStarted) {
Thread.sleep(100);
}
}
await(
() ->
fx(
() ->
Window.getWindows().stream()
.anyMatch(
w ->
w instanceof Stage s
&& s.getScene() != null
&& s.getScene().getRoot()
instanceof DesignerPane)));
var pane =
fx(
() ->
(DesignerPane)
Window.getWindows().stream()
.filter(
w ->
w instanceof Stage s
&& s.getScene() != null
&& s.getScene().getRoot() instanceof DesignerPane)
.map(w -> ((Stage) w).getScene().getRoot())
.findFirst()
.orElseThrow());
await(() -> fx(() -> pane.kit().editor().getFxomDocument() != null));
fx(
() -> {
pane.lookupAll(".button").stream()
.filter(
n -> n instanceof Button b && b.getText().equals("Build and Refresh"))
.map(n -> (Button) n)
.findFirst()
.orElseThrow()
.fire();
return null;
});
await(
() ->
fx(
() -> {
var item =
new FXOMFxIdIndex(pane.kit().editor().getFxomDocument())
.lookup("homeForm");
return item instanceof FXOMInstance i
&& i.getSceneGraphObject() instanceof SnapshotRegion r
&& r.image() != null
&& r.statusText().equals("Target runtime");
}));
System.out.println(
"PASS real fx-example Build and Refresh and canvas Component pixels");
var member = DesignerPane.class.getDeclaredField("launch");
member.setAccessible(true);
var launch = fx(() -> (HostLaunch) member.get(pane));
Path desk =
library.resolve(
"fx-example/src/main/resources/de/neitzel/fx/example/view/Desk.fxml");
var host = pane.kit().host();
try (var workflow =
new DesignerWorkflow(
host,
launch.configuration(),
launch.context(),
launch.maven(),
launch.tools(),
System.out::println);
var document =
host.documents().open(desk.toUri()).toCompletableFuture().get()) {
var original = document.snapshot().toCompletableFuture().get();
var metadata =
workflow
.bindings(false, original, "name", "both")
.toCompletableFuture()
.get(60, TimeUnit.SECONDS);
check(
metadata.model().equals("de.neitzel.fx.example.model.Person"),
"Wrong declared Model");
check(
metadata.diagnostics().stream()
.anyMatch(s -> s.contains("Generated Model metadata")),
"Generated metadata not used");
check(
metadata.problems().stream().noneMatch(p -> p.severity().equals("ERROR")),
"Binding errors: " + metadata.problems());
String edited = original.text() + "\n<!-- documented-example edit -->\n";
document
.apply(
new EditBatch(
original.revision(),
"Reference example edit",
List.of(
new EditBatch.Replacement(0, original.text().length(), edited))))
.toCompletableFuture()
.get();
check(
document.undo().toCompletableFuture().get().text().equals(original.text()),
"Undo changed source");
check(
document.redo().toCompletableFuture().get().text().equals(edited),
"Redo changed source");
var draft = document.snapshot().toCompletableFuture().get();
document.save(draft.revision()).toCompletableFuture().get();
check(Files.readString(desk).equals(edited), "Save changed source");
var restored = document.undo().toCompletableFuture().get();
document.save(restored.revision()).toCompletableFuture().get();
var examples =
workflow
.examplesFor(false, desk.toUri())
.toCompletableFuture()
.get(60, TimeUnit.SECONDS);
check(
examples.size() == 1 && examples.getFirst().id().equals("desk"),
"Wrong desk samples: " + examples);
workflow
.interactive(
false, "desk", List.of(document.snapshot().toCompletableFuture().get()))
.toCompletableFuture()
.get(60, TimeUnit.SECONDS);
workflow.cancel();
int windows = fx(() -> Window.getWindows().size());
var child =
workflow
.componentSource("de.neitzel.fx.example.view.AddressForm")
.toCompletableFuture()
.get(60, TimeUnit.SECONDS);
host.navigation()
.open(new HostServices.Location(child, 0))
.toCompletableFuture()
.get();
await(() -> fx(() -> Window.getWindows().size() == windows + 1));
host.navigation()
.open(new HostServices.Location(child, 0))
.toCompletableFuture()
.get();
check(
fx(() -> Window.getWindows().size()) == windows + 1,
"Duplicate Component editor");
for (var spec :
List.of(
new String[] {"AddressForm", "address"},
new String[] {"VisitForm", "visit"},
new String[] {"VisitRow", "row"},
new String[] {"NoteForm", "note"})) {
var path = desk.resolveSibling(spec[0] + ".fxml");
var choices =
workflow
.examplesFor(false, path.toUri())
.toCompletableFuture()
.get(60, TimeUnit.SECONDS);
check(
choices.size() == 1 && choices.getFirst().id().equals(spec[1]),
"Wrong component samples: " + choices);
try (var component =
host.documents().open(path.toUri()).toCompletableFuture().get()) {
workflow
.interactive(
false,
spec[1],
List.of(
document.snapshot().toCompletableFuture().get(),
component.snapshot().toCompletableFuture().get()))
.toCompletableFuture()
.get(60, TimeUnit.SECONDS);
workflow.cancel();
}
}
System.out.println(
"PASS real fx-example metadata, source history/save, navigation and all five"
+ " independent interactive samples");
}
Files.writeString(
output.resolve("workers.txt"),
String.join(
"\n",
ProcessHandle.current()
.descendants()
.map(p -> Long.toString(p.pid()))
.toList()));
fx(
() -> {
for (var window : List.copyOf(Window.getWindows()))
if (window instanceof Stage stage) {
stage.setOnCloseRequest(null);
stage.close();
}
return null;
});
Files.writeString(
output.resolve("SUCCESS.txt"),
"PASS packaged designer with real NeitzelLib fx-example\n");
Platform.exit();
} catch (Throwable e) {
try (var out =
new java.io.PrintWriter(
Files.newBufferedWriter(output.resolve("FAILURE.txt")))) {
e.printStackTrace(out);
} catch (Exception ignoredWrite) {
}
e.printStackTrace();
System.exit(1);
}
});
}
}