From: David Roden Date: Mon, 27 Jan 2025 20:44:33 +0000 (+0100) Subject: ✅ Fix tests that checks for a window’s component hierarchy X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=1cd36e01d41ad6ee327d3d96bdc8fbfd62fdfa1e;p=msta.git ✅ Fix tests that checks for a window’s component hierarchy --- diff --git a/server/src/main/java/de/qsheltier/msta/Server.java b/server/src/main/java/de/qsheltier/msta/Server.java index 4ca790b..cb12dbb 100644 --- a/server/src/main/java/de/qsheltier/msta/Server.java +++ b/server/src/main/java/de/qsheltier/msta/Server.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.awt.Component; +import java.awt.Container; import java.awt.Frame; import java.awt.Window; import java.io.BufferedReader; @@ -24,10 +25,14 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import javax.swing.JButton; +import javax.swing.JLabel; import javax.swing.SwingUtilities; import static java.nio.charset.StandardCharsets.UTF_8; @@ -150,7 +155,7 @@ public class Server implements Closeable { var newWindows = currentlyOpenWindows.stream().filter(window -> !windows.containsValue(window)).toList(); newWindows.forEach(newWindow -> { synchronized (outputWriters) { - outputWriters.forEach(writeLine -> writeLine.accept(createEvent("window-opened", getWindowObject(newWindow)))); + outputWriters.forEach(writeLine -> writeLine.accept(createEvent("window-opened", getComponentObject(newWindow)))); } windows.put(newWindow.getName(), newWindow); }); @@ -187,7 +192,7 @@ public class Server implements Closeable { if (words.getFirst().equalsIgnoreCase("info") && (words.size() == 3) && words.get(1).equalsIgnoreCase("window")) { var windowName = words.get(2); stream(Window.getWindows()).filter(window -> window.getName().equals(windowName)) - .forEach(window -> writeLine.accept(createMessage(getWindowObject(window).put("info", "window")))); + .forEach(window -> writeLine.accept(createMessage(getComponentObject(window).put("info", "window")))); } } } finally { @@ -198,11 +203,27 @@ public class Server implements Closeable { } } - private ObjectNode getWindowObject(Window window) { - var windowNode = objectMapper.createObjectNode(); - windowNode.put("id", window.getName()); - windowNode.put("is-frame", window instanceof Frame); - return windowNode; + private ObjectNode getComponentObject(Component component) { + var componentNode = objectMapper.createObjectNode(); + componentNode.put("id", componentIds.computeIfAbsent(component, c -> idCounter.incrementAndGet())); + componentNode.put("type", component.getClass().getName()); + switch (component) { + case Frame frame -> componentNode.put("title", frame.getTitle()); + case JButton button -> componentNode.put("text", button.getText()); + case JLabel label -> componentNode.put("text", label.getText()); + case Container container -> { + var childrenNode = componentNode.putArray("children"); + synchronized (component.getTreeLock()) { + stream(container.getComponents()) + .filter(Component::isVisible) + .map(this::getComponentObject) + .forEach(childrenNode::add); + } + } + default -> { + } + } + return componentNode; } private String createEvent(String name, ObjectNode parameters) { @@ -224,5 +245,7 @@ public class Server implements Closeable { private final AtomicBoolean closed = new AtomicBoolean(false); private final Set> outputWriters = new HashSet<>(); private final Map windows = new ConcurrentHashMap<>(); + private final AtomicInteger idCounter = new AtomicInteger(); + private final WeakHashMap componentIds = new WeakHashMap<>(); } diff --git a/server/src/test/java/de/qsheltier/msta/ServerTest.java b/server/src/test/java/de/qsheltier/msta/ServerTest.java index 780826f..95e6c9e 100644 --- a/server/src/test/java/de/qsheltier/msta/ServerTest.java +++ b/server/src/test/java/de/qsheltier/msta/ServerTest.java @@ -1,6 +1,7 @@ package de.qsheltier.msta; import com.fasterxml.jackson.databind.ObjectMapper; +import java.awt.BorderLayout; import java.awt.Frame; import java.awt.Window; import java.io.BufferedReader; @@ -17,16 +18,23 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Supplier; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import static com.spotify.hamcrest.jackson.JsonMatchers.isJsonStringMatching; -import static com.spotify.hamcrest.jackson.JsonMatchers.jsonBoolean; -import static com.spotify.hamcrest.jackson.JsonMatchers.jsonMissing; +import static com.spotify.hamcrest.jackson.JsonMatchers.jsonArray; +import static com.spotify.hamcrest.jackson.JsonMatchers.jsonInt; import static com.spotify.hamcrest.jackson.JsonMatchers.jsonObject; import static com.spotify.hamcrest.jackson.JsonMatchers.jsonText; import static java.nio.charset.StandardCharsets.UTF_8; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Timeout.ThreadMode.SEPARATE_THREAD; @@ -185,19 +193,25 @@ public class ServerTest { @Test @Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode = SEPARATE_THREAD) - public void windowInfoContainsButtonInfo() throws Throwable { + public void windowInfoContainsInfoAboutAllComponents() throws Throwable { connectToServer(verifyConnectedEvent((reader, ready, writer) -> { var window = new Window(null); - window.setVisible(true); + SwingUtilities.invokeAndWait(() -> { + var mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(new JLabel("Label"), BorderLayout.NORTH); + mainPanel.add(new JButton("Button"), BorderLayout.SOUTH); + window.add(mainPanel); + window.pack(); + window.setVisible(true); + }); try { var reply = objectMapper.readTree(reader.get()); - assertThat(reply, jsonObject().where("event", jsonText("window-opened")).where("id", not(jsonMissing()))); - var windowName = reply.get("id").asText(); - writer.accept("info window " + windowName); - reply = objectMapper.readTree(reader.get()); - assertThat(reply, jsonObject() - .where("info", jsonText("window")) - .where("id", jsonText(windowName)) + System.out.println(reply); + assertThat(reply, jsonObject().where("event", jsonText("window-opened")).where("id", jsonInt(anything())) + .where("children", jsonArray(contains(jsonObject().where("type", jsonText("javax.swing.JPanel")) + .where("children", jsonArray(containsInAnyOrder( + jsonObject().where("type", jsonText("javax.swing.JLabel")), + jsonObject().where("type", jsonText("javax.swing.JButton")))))))) ); } finally { window.setVisible(false);