From 82d6230592a63493def3e37f31758106ec4927f0 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Wed, 29 Oct 2025 11:40:22 +0000 Subject: [PATCH 1/9] feat: Update buttplug4j to the v4 spec This will only work with the Interface Central v3 release, currently in beta. # Conflicts: # buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java # buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java # buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java # buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java # buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java # buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java # buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java # buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java # buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java # buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java --- .../ButtplugClientWSJettyClientTest.java | 119 ++++++++---------- .../client/ButtplugClientDevice.java | 10 +- .../client/ButtplugClientDeviceFeature.java | 62 --------- .../protocol/messages/DeviceFeature.java | 2 +- .../protocol/messages/InputCmd.java | 8 +- .../protocol/messages/InputReading.java | 32 +---- .../protocol/messages/ServerInfo.java | 34 ++--- .../buttplug4j/client/InputReadingTest.java | 45 +++++++ .../protocol/messages/DeviceListTest.java | 2 +- .../protocol/messages/ServerInfoTest.java | 6 +- .../protocol/messages/TestConstants.java | 2 +- 11 files changed, 133 insertions(+), 189 deletions(-) create mode 100644 buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java diff --git a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java index 1bf6c6a..8c25b63 100644 --- a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java +++ b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java @@ -1,93 +1,80 @@ package io.github.blackspherefollower.buttplug4j.connectors.jetty.websocket.client; import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDevice; -import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDeviceFeature; -import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceFeatureException; -import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient; -import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; -import io.github.blackspherefollower.buttplug4j.protocol.messages.InputReading; - +import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceException; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.IOException; import java.net.URI; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ButtplugClientWSJettyClientTest { - + @Disabled @Test public void TestConnect() throws Exception { - try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { - Thread.sleep(500); - WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); - Thread.sleep(500); - - ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); - client.connect(new URI("ws://localhost:" + wrapper.cport + "/buttplug")); - client.startScanning(); + ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); + client.connect(new URI("ws://localhost:12345/buttplug")); + client.startScanning(); + + Thread.sleep(5000); + client.requestDeviceList(); + for (ButtplugClientDevice dev : client.getDevices()) { + if (dev.getScalarVibrateCount() > 0) { + dev.sendScalarVibrateCmd(0.5).get(); + } + } - Thread.sleep(500); - client.requestDeviceList(); + Thread.sleep(1000); + assertTrue(client.stopAllDevices()); - assertEquals(1, client.getDevices().size()); - for (ButtplugClientDevice dev : client.getDevices()) { - for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { - if (feat.HasVibrate()) { - feat.VibrateFloat(0.5F).get(); - } - } + Thread.sleep(60000); + for (ButtplugClientDevice dev : client.getDevices()) { + if (dev.getScalarVibrateCount() > 0) { + dev.sendScalarVibrateCmd(0.5).get(); } + } - Thread.sleep(500); - assertEquals("Vibrate:10;", wsdev.messages.poll()); - - assertTrue(client.stopAllDevices()); - Thread.sleep(500); - assertEquals("Vibrate:0;", wsdev.messages.poll()); + Thread.sleep(1000); + assertTrue(client.stopAllDevices()); - client.disconnect(); + Thread.sleep(60000); + for (ButtplugClientDevice dev : client.getDevices()) { + if (dev.getScalarVibrateCount() > 0) { + dev.sendScalarVibrateCmd(0.5).get(); + } } + + Thread.sleep(1000); + assertTrue(client.stopAllDevices()); + + client.disconnect(); } + @Disabled @Test - @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void TestBattery() throws Exception { - try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { - Thread.sleep(500); - WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); - Thread.sleep(500); - - ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); - client.connect(new URI("ws://localhost:" + wrapper.cport + "/buttplug")); - client.startScanning(); - - Thread.sleep(500); - client.requestDeviceList(); - for (ButtplugClientDevice dev : client.getDevices()) { - for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { - if (feat.HasBattery()) { - ButtplugMessage res = feat.ReadBattery().get(); - if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) { - InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData(); - int battery = reading.getValue(); - System.out.println("Battery is " + battery); - assertTrue(battery >= 0); - assertTrue(battery <= 100); - } - } else { - assertThrows(ButtplugDeviceFeatureException.class, () -> { - feat.ReadBattery().get(); - }); - } - } + ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); + client.connect(new URI("ws://localhost:12345/buttplug")); + client.startScanning(); + + Thread.sleep(2000); + client.requestDeviceList(); + for (ButtplugClientDevice dev : client.getDevices()) { + if (dev.hasBatterySensor()) { + long battery = dev.readBatteryLevel(); + System.out.println("Battery is " + battery); + assertTrue(battery >= 0); + assertTrue(battery <= 100); + } else { + assertThrows(ButtplugDeviceException.class, () -> { + long battery = dev.readBatteryLevel(); + }); } - - client.disconnect(); } + + client.disconnect(); } } \ No newline at end of file diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java index 8a86e5e..9ccd7c3 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java @@ -1,7 +1,10 @@ package io.github.blackspherefollower.buttplug4j.client; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; -import io.github.blackspherefollower.buttplug4j.protocol.messages.*; +import io.github.blackspherefollower.buttplug4j.protocol.messages.Device; +import io.github.blackspherefollower.buttplug4j.protocol.messages.DeviceFeature; +import io.github.blackspherefollower.buttplug4j.protocol.messages.OutputCmd; +import io.github.blackspherefollower.buttplug4j.protocol.messages.StopDeviceCmd; import java.util.HashMap; import java.util.Map; @@ -63,11 +66,6 @@ public Future sendOutputCommand(int featureIndex, OutputCmd.IOu return client.sendMessage(cmd); } - public Future sendInputCommand(int featureIndex, final String inputType, final InputCommandType inputCommand) { - InputCmd cmd = new InputCmd(client.getNextMsgId(), deviceIndex, featureIndex, inputType, inputCommand); - return client.sendMessage(cmd); - } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java index 119e414..78f87ea 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java @@ -2,8 +2,6 @@ import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; import io.github.blackspherefollower.buttplug4j.protocol.messages.DeviceFeature; -import io.github.blackspherefollower.buttplug4j.protocol.messages.InputCmd; -import io.github.blackspherefollower.buttplug4j.protocol.messages.InputCommandType; import io.github.blackspherefollower.buttplug4j.protocol.messages.OutputCmd; import java.util.HashMap; @@ -72,10 +70,6 @@ private void CheckStepRange(final String type, final float value) throws Buttplu } } - public boolean HasVibrate() { - return output.get("Vibrate") != null; - } - public Future Vibrate(final int vibrate) throws ButtplugDeviceFeatureException { CheckStepRange("Vibrate", vibrate); return device.sendOutputCommand(featureIndex, new OutputCmd.Vibrate(vibrate)); @@ -85,10 +79,6 @@ public Future VibrateFloat(final float vibrate) throws Buttplug return device.sendOutputCommand(featureIndex, new OutputCmd.Vibrate(GetStepFromFloat("Vibrate", vibrate))); } - public boolean HasRotate() { - return output.get("Rotate") != null; - } - public Future Rotate(final int rotate) throws ButtplugDeviceFeatureException { CheckStepRange("Rotate", rotate); return device.sendOutputCommand(featureIndex, new OutputCmd.Rotate(rotate)); @@ -98,10 +88,6 @@ public Future RotateFloat(final float rotate) throws ButtplugDe return device.sendOutputCommand(featureIndex, new OutputCmd.Rotate(GetStepFromFloat("Rotate", rotate))); } - public boolean HasConstrict() { - return output.get("Constrict") != null; - } - public Future Constrict(final int constrict) throws ButtplugDeviceFeatureException { CheckStepRange("Constrict", constrict); return device.sendOutputCommand(featureIndex, new OutputCmd.Constrict(constrict)); @@ -111,10 +97,6 @@ public Future ConstrictFloat(final float constrict) throws Butt return device.sendOutputCommand(featureIndex, new OutputCmd.Constrict(GetStepFromFloat("Constrict", constrict))); } - public boolean HasSpray() { - return output.get("Spray") != null; - } - public Future Spray(final int spray) throws ButtplugDeviceFeatureException { CheckStepRange("Spray", spray); return device.sendOutputCommand(featureIndex, new OutputCmd.Spray(spray)); @@ -124,10 +106,6 @@ public Future SprayFloat(final float spray) throws ButtplugDevi return device.sendOutputCommand(featureIndex, new OutputCmd.Spray(GetStepFromFloat("Spray", spray))); } - public boolean HasPosition() { - return output.get("Position") != null; - } - public Future Position(final int position) throws ButtplugDeviceFeatureException { CheckStepRange("Position", position); return device.sendOutputCommand(featureIndex, new OutputCmd.Position(position)); @@ -137,10 +115,6 @@ public Future PositionFloat(final float position) throws Buttpl return device.sendOutputCommand(featureIndex, new OutputCmd.Position(GetStepFromFloat("Position", position))); } - public boolean HasPositionWithDuration() { - return output.get("PositionWithDuration") != null; - } - public Future PositionWithDuration(final int position, final int duration) throws ButtplugDeviceFeatureException { CheckStepRange("PositionWithDuration", position); return device.sendOutputCommand(featureIndex, new OutputCmd.PositionWithDuration(position, duration)); @@ -150,10 +124,6 @@ public Future PositionWithDurationFloat(final float position, f return device.sendOutputCommand(featureIndex, new OutputCmd.PositionWithDuration(GetStepFromFloat("PositionWithDuration", position), duration)); } - public boolean HasLed() { - return output.get("Led") != null; - } - public Future Led(final int led) throws ButtplugDeviceFeatureException { CheckStepRange("Led", led); return device.sendOutputCommand(featureIndex, new OutputCmd.Led(led)); @@ -163,10 +133,6 @@ public Future LedFloat(final float led) throws ButtplugDeviceFe return device.sendOutputCommand(featureIndex, new OutputCmd.Led(GetStepFromFloat("Led", led))); } - public boolean HasOscillate() { - return output.get("Oscillate") != null; - } - public Future Oscillate(final int oscillate) throws ButtplugDeviceFeatureException { CheckStepRange("Oscillate", oscillate); return device.sendOutputCommand(featureIndex, new OutputCmd.Oscillate(oscillate)); @@ -176,10 +142,6 @@ public Future OscillateFloat(final float oscillate) throws Butt return device.sendOutputCommand(featureIndex, new OutputCmd.Oscillate(GetStepFromFloat("Oscillate", oscillate))); } - public boolean HasTemperature() { - return output.get("Temperature") != null; - } - public Future Temperature(final int temperature) throws ButtplugDeviceFeatureException { CheckStepRange("Temperature", temperature); return device.sendOutputCommand(featureIndex, new OutputCmd.Temperature(temperature)); @@ -189,30 +151,6 @@ public Future TemperatureFloat(final float temperature) throws return device.sendOutputCommand(featureIndex, new OutputCmd.Temperature(GetStepFromFloat("Temperature", temperature))); } - private void CheckInput(final String type) throws ButtplugDeviceFeatureException { - if (input.get(type) == null) { - throw new ButtplugDeviceFeatureException(type); - } - } - - public boolean HasBattery() { - return input.get("Battery") != null; - } - - public Future ReadBattery() throws ButtplugDeviceFeatureException { - CheckInput("Battery"); - return device.sendInputCommand(featureIndex, "Battery", InputCommandType.READ); - } - - public boolean HasRssi() { - return input.get("Rssi") != null; - } - - public Future ReadRssi() throws ButtplugDeviceFeatureException { - CheckInput("Rssi"); - return device.sendInputCommand(featureIndex, "Rssi", InputCommandType.READ); - } - public String getDescription() { return description; } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java index 7ee4176..7545ab5 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java @@ -243,7 +243,7 @@ public boolean equals(Object o) { @JsonSubTypes.Type(value = DeviceFeature.PositionInput.class, name = "Position") }) public static class InputDescriptor { - @JsonProperty(value = "InputCommands", required = true) + @JsonProperty(value = "InputCommandType", required = true) private ArrayList input; public InputDescriptor(ArrayList input) { diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java index b6ffba8..86d8f79 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java @@ -6,7 +6,7 @@ public class InputCmd extends ButtplugDeviceMessage { @JsonProperty(value = "FeatureIndex", required = true) - private int featureIndex; + private long featureIndex; @JsonProperty(value = "InputType", required = true) private String inputType; @@ -14,7 +14,7 @@ public class InputCmd extends ButtplugDeviceMessage { @JsonProperty(value = "InputCommand", required = true) private InputCommandType inputCommand; - public InputCmd(int id, final long deviceIndex, final int featureIndex, final String inputType, final InputCommandType inputCommand) { + public InputCmd(int id, final long deviceIndex, final long featureIndex, final String inputType, final InputCommandType inputCommand) { super(id, deviceIndex); this.featureIndex = featureIndex; this.inputType = inputType; @@ -29,11 +29,11 @@ public InputCmd() { } - public int getFeatureIndex() { + public long getFeatureIndex() { return featureIndex; } - public void setFeatureIndex(int featureIndex) { + public void setFeatureIndex(long featureIndex) { this.featureIndex = featureIndex; } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java index ad0846e..880a28e 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java @@ -15,47 +15,23 @@ public InputReading(int id, long deviceIndex, int featureIndex) { this.featureIndex = featureIndex; } - public InputData getData() { - return data; - } - - public void setData(InputData data) { - this.data = data; - } - - public int getFeatureIndex() { - return featureIndex; - } - - public void setFeatureIndex(int featureIndex) { - this.featureIndex = featureIndex; - } - public interface InputData { } static public class InputIntegerData { @JsonProperty(value = "Data", required = true) int value; - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } } - static public class BatteryData extends InputIntegerData { + static public class BatteryData implements InputData { } - static public class RssiData extends InputIntegerData { + static public class RssiData implements InputData { } - static public class ButtonData extends InputIntegerData { + static public class ButtonData implements InputData { } - static public class PresureData extends InputIntegerData { + static public class PresureData implements InputData { } } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java index 6e6de43..40c118f 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java @@ -6,11 +6,11 @@ public final class ServerInfo extends ButtplugMessage { - @JsonProperty(value = "ProtocolVersionMajor", required = true) - private int protocolVersionMajor; + @JsonProperty(value = "ProtocolMajorVersion", required = true) + private int protocolMajorVersion; - @JsonProperty(value = "ProtocolVersionMinor", required = true) - private int protocolVersionMinor; + @JsonProperty(value = "ProtocolMinorVersion", required = true) + private int protocolMinorVersion; @JsonProperty(value = "MaxPingTime", required = true) private long maxPingTime; @@ -18,12 +18,12 @@ public final class ServerInfo extends ButtplugMessage { @JsonProperty(value = "ServerName", required = true) private String serverName; - public ServerInfo(final String serverName, final int protocolVersionMajor, final int protocolVersionMinor, final long maxPingTime, final int id) { + public ServerInfo(final String serverName, final int protocolMajorVersion, final int protocolMinorVersion, final long maxPingTime, final int id) { super(id); this.serverName = serverName; - this.protocolVersionMajor = protocolVersionMajor; - this.protocolVersionMinor = protocolVersionMinor; + this.protocolMajorVersion = protocolMajorVersion; + this.protocolMinorVersion = protocolMinorVersion; this.maxPingTime = maxPingTime; } @@ -32,25 +32,25 @@ private ServerInfo() { super(ButtplugConsts.DEFAULT_MSG_ID); this.serverName = ""; - this.protocolVersionMajor = 4; - this.protocolVersionMinor = 0; + this.protocolMajorVersion = 4; + this.protocolMinorVersion = 0; this.maxPingTime = 0; } - public int getProtocolVersionMajor() { - return protocolVersionMajor; + public int getProtocolMajorVersion() { + return protocolMajorVersion; } - public void setProtocolVersionMajor(final int protocolVersionMajor) { - this.protocolVersionMajor = protocolVersionMajor; + public void setProtocolMajorVersion(final int protocolMajorVersion) { + this.protocolMajorVersion = protocolMajorVersion; } - public int getProtocolVersionMinor() { - return protocolVersionMinor; + public int getProtocolMinorVersion() { + return protocolMinorVersion; } - public void setProtocolVersionMinor(final int protocolVersionMinor) { - this.protocolVersionMinor = protocolVersionMinor; + public void setProtocolMinorVersion(final int protocolMinorVersion) { + this.protocolMinorVersion = protocolMinorVersion; } public long getMaxPingTime() { diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java new file mode 100644 index 0000000..91562a5 --- /dev/null +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java @@ -0,0 +1,45 @@ +package io.github.blackspherefollower.buttplug4j.protocol.messages; + +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugDeviceMessage; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugJsonMessageParser; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugProtocolException; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class InputReadingTest { + + @Test + public void testInputReadingCreation() { + InputReading reading = new InputReading(1, 0, 0); + + assertEquals(1, reading.getId()); + assertEquals(0, reading.getDeviceIndex()); + assertNotNull(reading); + } + + @Test + public void testInputReadingInheritance() { + InputReading reading = new InputReading(1, 0, 0); + + assertInstanceOf(ButtplugDeviceMessage.class, reading); + } + + @Test + public void testInputDataInterfaces() { + // Test that InputData interface classes exist + InputReading.BatteryData batteryData = new InputReading.BatteryData(); + InputReading.RssiData rssiData = new InputReading.RssiData(); + InputReading.ButtonData buttonData = new InputReading.ButtonData(); + InputReading.PresureData presureData = new InputReading.PresureData(); + + assertInstanceOf(InputReading.InputData.class, batteryData); + assertInstanceOf(InputReading.InputData.class, rssiData); + assertInstanceOf(InputReading.InputData.class, buttonData); + assertInstanceOf(InputReading.InputData.class, presureData); + } +} diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java index f42a29f..a9275c1 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java @@ -33,7 +33,7 @@ public static void setup() throws IOException { @Test public void test() throws IOException, ButtplugProtocolException { - String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"InputCommands\":[\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Position\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"InputCommands\":[\"Subscribe\",\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"InputCommands\":[\"Read\"],\"ValueRange\":[[-10,0],[-100,0]]}}}}}}}}]"; + String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"InputCommandType\":[\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Position\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"InputCommandType\":[\"Subscribe\",\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"InputCommandType\":[\"Read\"],\"ValueRange\":[[-10,0],[-100,0]]}}}}}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java index e390ebf..213a043 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java @@ -34,7 +34,7 @@ public static void setup() throws IOException { @Test public void test() throws IOException, ButtplugProtocolException { - String testStr = "[{\"ServerInfo\":{\"Id\":1,\"ProtocolVersionMajor\":4,\"ProtocolVersionMinor\":0,\"MaxPingTime\":500,\"ServerName\":\"Websocket Server\"}}]"; + String testStr = "[{\"ServerInfo\":{\"Id\":1,\"ProtocolMajorVersion\":4,\"ProtocolMinorVersion\":0,\"MaxPingTime\":500,\"ServerName\":\"Websocket Server\"}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(Error::getError).collect(Collectors.joining("\n"))); @@ -45,8 +45,8 @@ public void test() throws IOException, ButtplugProtocolException { assertEquals(1, msgs.size()); assertEquals(ServerInfo.class, msgs.get(0).getClass()); assertEquals(1, msgs.get(0).getId(), 1); - assertEquals(4, ((ServerInfo) msgs.get(0)).getProtocolVersionMajor()); - assertEquals(0, ((ServerInfo) msgs.get(0)).getProtocolVersionMinor()); + assertEquals(4, ((ServerInfo) msgs.get(0)).getProtocolMajorVersion()); + assertEquals(0, ((ServerInfo) msgs.get(0)).getProtocolMinorVersion()); assertEquals(500, ((ServerInfo) msgs.get(0)).getMaxPingTime()); assertEquals("Websocket Server", ((ServerInfo) msgs.get(0)).getServerName()); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java index 1cee321..c0bc13b 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java @@ -1,5 +1,5 @@ package io.github.blackspherefollower.buttplug4j.protocol.messages; public class TestConstants { - static public final String SCHEMA_URL = "https://raw.githubusercontent.com/buttplugio/buttplug/refs/heads/dev/crates/buttplug_core/schema/buttplug-schema.json"; + static public final String SCHEMA_URL = "https://raw.githubusercontent.com/buttplugio/buttplug/refs/heads/master/crates/buttplug_core/schema/buttplug-schema.json"; } From 22c9f57f1330858fe1ca6698852d70d011370bb7 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 2 Dec 2025 15:24:41 +0000 Subject: [PATCH 2/9] wip: Adding intiface-engine based tests --- .../ButtplugClientWSJettyClientTest.java | 118 +++++++++-------- buttplug4j.utils.test/build.gradle | 4 +- .../buttplug4j/utils/test/WSDMClient.java | 122 +++++++++--------- .../client/ButtplugClientDevice.java | 10 +- .../client/ButtplugClientDeviceFeature.java | 62 +++++++++ .../protocol/messages/DeviceFeature.java | 2 +- .../protocol/messages/InputCmd.java | 8 +- .../protocol/messages/InputReading.java | 32 ++++- .../protocol/messages/ServerInfo.java | 34 ++--- .../buttplug4j/client/InputReadingTest.java | 45 ------- .../protocol/messages/DeviceListTest.java | 2 +- .../protocol/messages/ServerInfoTest.java | 6 +- .../protocol/messages/TestConstants.java | 2 +- 13 files changed, 251 insertions(+), 196 deletions(-) delete mode 100644 buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java diff --git a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java index 8c25b63..8595068 100644 --- a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java +++ b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java @@ -1,80 +1,92 @@ package io.github.blackspherefollower.buttplug4j.connectors.jetty.websocket.client; import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDevice; -import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceException; +import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDeviceFeature; +import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceFeatureException; +import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient; +import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; +import io.github.blackspherefollower.buttplug4j.protocol.messages.InputReading; + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import java.io.File; +import java.io.IOException; import java.net.URI; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class ButtplugClientWSJettyClientTest { - @Disabled + @Test public void TestConnect() throws Exception { - ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); - client.connect(new URI("ws://localhost:12345/buttplug")); - client.startScanning(); - - Thread.sleep(5000); - client.requestDeviceList(); - for (ButtplugClientDevice dev : client.getDevices()) { - if (dev.getScalarVibrateCount() > 0) { - dev.sendScalarVibrateCmd(0.5).get(); - } - } + try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { + Thread.sleep(500); + WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); + Thread.sleep(500); - Thread.sleep(1000); - assertTrue(client.stopAllDevices()); - - Thread.sleep(60000); - for (ButtplugClientDevice dev : client.getDevices()) { - if (dev.getScalarVibrateCount() > 0) { - dev.sendScalarVibrateCmd(0.5).get(); - } - } + ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); + client.connect(new URI("ws://localhost:" + wrapper.cport + "/buttplug")); + client.startScanning(); - Thread.sleep(1000); - assertTrue(client.stopAllDevices()); + Thread.sleep(500); + client.requestDeviceList(); - Thread.sleep(60000); - for (ButtplugClientDevice dev : client.getDevices()) { - if (dev.getScalarVibrateCount() > 0) { - dev.sendScalarVibrateCmd(0.5).get(); + assertEquals(1, client.getDevices().size()); + for (ButtplugClientDevice dev : client.getDevices()) { + for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { + if (feat.HasVibrate()) { + feat.VibrateFloat(0.5F).get(); + } + } } - } + assertEquals(wsdev.messages.poll(), "DeviceType;"); + assertEquals(wsdev.messages.poll(), "Vibrate:10;"); - Thread.sleep(1000); - assertTrue(client.stopAllDevices()); + Thread.sleep(500); + assertTrue(client.stopAllDevices()); + assertEquals(wsdev.messages.poll(), "Vibrate:0;"); - client.disconnect(); + client.disconnect(); + } } - @Disabled @Test + @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void TestBattery() throws Exception { - ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); - client.connect(new URI("ws://localhost:12345/buttplug")); - client.startScanning(); - - Thread.sleep(2000); - client.requestDeviceList(); - for (ButtplugClientDevice dev : client.getDevices()) { - if (dev.hasBatterySensor()) { - long battery = dev.readBatteryLevel(); - System.out.println("Battery is " + battery); - assertTrue(battery >= 0); - assertTrue(battery <= 100); - } else { - assertThrows(ButtplugDeviceException.class, () -> { - long battery = dev.readBatteryLevel(); - }); + try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { + Thread.sleep(500); + WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); + Thread.sleep(500); + + ButtplugClientWSClient client = new ButtplugClientWSClient("Java Test"); + client.connect(new URI("ws://localhost:" + wrapper.cport + "/buttplug")); + client.startScanning(); + + Thread.sleep(500); + client.requestDeviceList(); + for (ButtplugClientDevice dev : client.getDevices()) { + for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { + if (feat.HasBattery()) { + ButtplugMessage res = feat.ReadBattery().get(); + if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) { + InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData(); + int battery = reading.getValue(); + System.out.println("Battery is " + battery); + assertTrue(battery >= 0); + assertTrue(battery <= 100); + } + } else { + assertThrows(ButtplugDeviceFeatureException.class, () -> { + feat.ReadBattery().get(); + }); + } + } } - } - client.disconnect(); + client.disconnect(); + } } } \ No newline at end of file diff --git a/buttplug4j.utils.test/build.gradle b/buttplug4j.utils.test/build.gradle index b98272d..076e0d4 100644 --- a/buttplug4j.utils.test/build.gradle +++ b/buttplug4j.utils.test/build.gradle @@ -12,12 +12,14 @@ repositories { dependencies { api project(":buttplug4j") + api 'org.eclipse.jetty.websocket:websocket-client:9.4.58.v20250814' + api 'org.eclipse.jetty.websocket:websocket-api:9.4.58.v20250814' api 'org.junit.jupiter:junit-jupiter:5.13.4' } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(8) } withJavadocJar() withSourcesJar() diff --git a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java index 8169d77..2c0836b 100644 --- a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java +++ b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java @@ -3,25 +3,36 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.blackspherefollower.buttplug4j.client.ButtplugClient; +import io.github.blackspherefollower.buttplug4j.client.IConnectedEvent; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugConsts; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; +import io.github.blackspherefollower.buttplug4j.protocol.ButtplugProtocolException; +import io.github.blackspherefollower.buttplug4j.protocol.messages.Error; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.annotations.*; +import org.eclipse.jetty.websocket.api.extensions.Frame; +import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.client.WebSocketClient; import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.WebSocket; import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.*; +@WebSocket(maxTextMessageSize = 64 * 1024) public class WSDMClient { - private WebSocket client; - private final WSDHeader header; + private WebSocketClient client; + private Session session; + private WSDHeader header; public ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); - private final CompletableFuture connected = new CompletableFuture<>(); + private CompletableFuture connected = new CompletableFuture<>(); public int battery = 100; - static class WSDHeader { + class WSDHeader { @JsonProperty("identifier") public String identifier; @JsonProperty("address") @@ -34,82 +45,64 @@ public WSDMClient(final URI url, final String identifier, final String address) header = new WSDHeader(); header.identifier = identifier; header.address = address; + client = new WebSocketClient(); - HttpClient - .newHttpClient() - .newWebSocketBuilder() - .buildAsync(url, new WebSocketClient(this)) - .join(); - connected.get(10, TimeUnit.SECONDS); - + client.start(); + client.connect(this, url, new ClientUpgradeRequest()).get(2, TimeUnit.SECONDS); + connected.get(5, TimeUnit.SECONDS); } - private static class WebSocketClient implements WebSocket.Listener { - WSDMClient wsdmclient; - public WebSocketClient(WSDMClient wsdmclient) {this.wsdmclient = wsdmclient;} - - @Override - public void onOpen(WebSocket webSocket) { - System.out.println("onOpen using subprotocol " + webSocket.getSubprotocol()); - wsdmclient.onConnect(webSocket); - WebSocket.Listener.super.onOpen(webSocket); - } - - @Override - public CompletionStage onText(WebSocket webSocket, CharSequence data, boolean last) { - System.out.println("onText received " + data); - wsdmclient.onMessage(data.toString()); - return WebSocket.Listener.super.onText(webSocket, data, last); - } + protected void cleanup() { - @Override - public void onError(WebSocket webSocket, Throwable error) { - System.out.println("Bad day! " + webSocket.toString()); - error.printStackTrace(); - WebSocket.Listener.super.onError(webSocket, error); - } + if (session != null) { + session.close(); + } - @Override - public CompletionStage onClose(WebSocket webSocket, int statusCode, String reason) { - System.out.println("onClose received " + statusCode + " " + reason); - wsdmclient.onClose(statusCode, reason); - return WebSocket.Listener.super.onClose(webSocket, statusCode, reason); + try { + LifeCycle.stop(client); + } catch (RuntimeException ignored) { + } + client = null; } - @Override - public CompletionStage onBinary(WebSocket webSocket, ByteBuffer message, boolean last) { - System.out.println("onBinary received " + message); - wsdmclient.onMessage(StandardCharsets.UTF_8.decode(message).toString()); - return WebSocket.Listener.super.onBinary(webSocket, message, last); - } - } - - + @OnWebSocketClose public void onClose(int statusCode, String reason) { - this.client = null; + this.session = null; + cleanup(); } - public void onConnect(WebSocket client) { - this.client = client; + @OnWebSocketConnect + public void onConnect(Session session) { + this.session = session; + // Don't block the WS thread new Thread(() -> { try { - client.sendText(new ObjectMapper().writeValueAsString(header), true).get(1, TimeUnit.SECONDS); + session.getRemote().sendStringByFuture(new ObjectMapper().writeValueAsString(header)).get(1, TimeUnit.SECONDS); } catch (JsonProcessingException | ExecutionException | InterruptedException |TimeoutException e) { System.out.println("Failed to send header: " + e.getMessage()); } }).start(); } - public void onMessage(final String message) { + @OnWebSocketFrame + public void onFrame(final Frame frame) { + if( frame.getType().isData()) { + System.out.println("Got frame: " + frame); + byte[] data = new byte[frame.getPayloadLength()]; + frame.getPayload().get(data); + onMessage(null, new String(data, StandardCharsets.UTF_8)); + } + } + + @OnWebSocketMessage + public void onMessage(final Session sess, final String message) { System.out.println("Got message: " + message); if(message.startsWith("DeviceType;")) { new Thread(() -> { try { - sendMessage("Z:10:" + header.address + ";"); - if(!connected.isDone()) { - connected.complete(true); - } + session.getRemote().sendBytesByFuture(ByteBuffer.wrap(("Z:10:" + header.address + ";").getBytes(StandardCharsets.UTF_8))).get(1, TimeUnit.SECONDS); + connected.complete(true); } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new RuntimeException(e); } @@ -120,7 +113,7 @@ public void onMessage(final String message) { if(message.startsWith("Battery;")) { new Thread(() -> { try { - sendMessage(battery + ";"); + session.getRemote().sendBytesByFuture(ByteBuffer.wrap((battery + ";").getBytes(StandardCharsets.UTF_8))).get(1, TimeUnit.SECONDS); connected.complete(true); } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new RuntimeException(e); @@ -132,7 +125,12 @@ public void onMessage(final String message) { messages.add(message); } + @OnWebSocketError + public void onWebSocketError(final Throwable cause) { + System.out.println("Got error: " + cause.getMessage()); + } + protected void sendMessage(final String msg) throws ExecutionException, InterruptedException, TimeoutException { - client.sendBinary(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)), true).get(1, TimeUnit.SECONDS); + session.getRemote().sendStringByFuture(msg).get(1, TimeUnit.SECONDS); } } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java index 9ccd7c3..8a86e5e 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDevice.java @@ -1,10 +1,7 @@ package io.github.blackspherefollower.buttplug4j.client; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; -import io.github.blackspherefollower.buttplug4j.protocol.messages.Device; -import io.github.blackspherefollower.buttplug4j.protocol.messages.DeviceFeature; -import io.github.blackspherefollower.buttplug4j.protocol.messages.OutputCmd; -import io.github.blackspherefollower.buttplug4j.protocol.messages.StopDeviceCmd; +import io.github.blackspherefollower.buttplug4j.protocol.messages.*; import java.util.HashMap; import java.util.Map; @@ -66,6 +63,11 @@ public Future sendOutputCommand(int featureIndex, OutputCmd.IOu return client.sendMessage(cmd); } + public Future sendInputCommand(int featureIndex, final String inputType, final InputCommandType inputCommand) { + InputCmd cmd = new InputCmd(client.getNextMsgId(), deviceIndex, featureIndex, inputType, inputCommand); + return client.sendMessage(cmd); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java index 78f87ea..119e414 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java @@ -2,6 +2,8 @@ import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; import io.github.blackspherefollower.buttplug4j.protocol.messages.DeviceFeature; +import io.github.blackspherefollower.buttplug4j.protocol.messages.InputCmd; +import io.github.blackspherefollower.buttplug4j.protocol.messages.InputCommandType; import io.github.blackspherefollower.buttplug4j.protocol.messages.OutputCmd; import java.util.HashMap; @@ -70,6 +72,10 @@ private void CheckStepRange(final String type, final float value) throws Buttplu } } + public boolean HasVibrate() { + return output.get("Vibrate") != null; + } + public Future Vibrate(final int vibrate) throws ButtplugDeviceFeatureException { CheckStepRange("Vibrate", vibrate); return device.sendOutputCommand(featureIndex, new OutputCmd.Vibrate(vibrate)); @@ -79,6 +85,10 @@ public Future VibrateFloat(final float vibrate) throws Buttplug return device.sendOutputCommand(featureIndex, new OutputCmd.Vibrate(GetStepFromFloat("Vibrate", vibrate))); } + public boolean HasRotate() { + return output.get("Rotate") != null; + } + public Future Rotate(final int rotate) throws ButtplugDeviceFeatureException { CheckStepRange("Rotate", rotate); return device.sendOutputCommand(featureIndex, new OutputCmd.Rotate(rotate)); @@ -88,6 +98,10 @@ public Future RotateFloat(final float rotate) throws ButtplugDe return device.sendOutputCommand(featureIndex, new OutputCmd.Rotate(GetStepFromFloat("Rotate", rotate))); } + public boolean HasConstrict() { + return output.get("Constrict") != null; + } + public Future Constrict(final int constrict) throws ButtplugDeviceFeatureException { CheckStepRange("Constrict", constrict); return device.sendOutputCommand(featureIndex, new OutputCmd.Constrict(constrict)); @@ -97,6 +111,10 @@ public Future ConstrictFloat(final float constrict) throws Butt return device.sendOutputCommand(featureIndex, new OutputCmd.Constrict(GetStepFromFloat("Constrict", constrict))); } + public boolean HasSpray() { + return output.get("Spray") != null; + } + public Future Spray(final int spray) throws ButtplugDeviceFeatureException { CheckStepRange("Spray", spray); return device.sendOutputCommand(featureIndex, new OutputCmd.Spray(spray)); @@ -106,6 +124,10 @@ public Future SprayFloat(final float spray) throws ButtplugDevi return device.sendOutputCommand(featureIndex, new OutputCmd.Spray(GetStepFromFloat("Spray", spray))); } + public boolean HasPosition() { + return output.get("Position") != null; + } + public Future Position(final int position) throws ButtplugDeviceFeatureException { CheckStepRange("Position", position); return device.sendOutputCommand(featureIndex, new OutputCmd.Position(position)); @@ -115,6 +137,10 @@ public Future PositionFloat(final float position) throws Buttpl return device.sendOutputCommand(featureIndex, new OutputCmd.Position(GetStepFromFloat("Position", position))); } + public boolean HasPositionWithDuration() { + return output.get("PositionWithDuration") != null; + } + public Future PositionWithDuration(final int position, final int duration) throws ButtplugDeviceFeatureException { CheckStepRange("PositionWithDuration", position); return device.sendOutputCommand(featureIndex, new OutputCmd.PositionWithDuration(position, duration)); @@ -124,6 +150,10 @@ public Future PositionWithDurationFloat(final float position, f return device.sendOutputCommand(featureIndex, new OutputCmd.PositionWithDuration(GetStepFromFloat("PositionWithDuration", position), duration)); } + public boolean HasLed() { + return output.get("Led") != null; + } + public Future Led(final int led) throws ButtplugDeviceFeatureException { CheckStepRange("Led", led); return device.sendOutputCommand(featureIndex, new OutputCmd.Led(led)); @@ -133,6 +163,10 @@ public Future LedFloat(final float led) throws ButtplugDeviceFe return device.sendOutputCommand(featureIndex, new OutputCmd.Led(GetStepFromFloat("Led", led))); } + public boolean HasOscillate() { + return output.get("Oscillate") != null; + } + public Future Oscillate(final int oscillate) throws ButtplugDeviceFeatureException { CheckStepRange("Oscillate", oscillate); return device.sendOutputCommand(featureIndex, new OutputCmd.Oscillate(oscillate)); @@ -142,6 +176,10 @@ public Future OscillateFloat(final float oscillate) throws Butt return device.sendOutputCommand(featureIndex, new OutputCmd.Oscillate(GetStepFromFloat("Oscillate", oscillate))); } + public boolean HasTemperature() { + return output.get("Temperature") != null; + } + public Future Temperature(final int temperature) throws ButtplugDeviceFeatureException { CheckStepRange("Temperature", temperature); return device.sendOutputCommand(featureIndex, new OutputCmd.Temperature(temperature)); @@ -151,6 +189,30 @@ public Future TemperatureFloat(final float temperature) throws return device.sendOutputCommand(featureIndex, new OutputCmd.Temperature(GetStepFromFloat("Temperature", temperature))); } + private void CheckInput(final String type) throws ButtplugDeviceFeatureException { + if (input.get(type) == null) { + throw new ButtplugDeviceFeatureException(type); + } + } + + public boolean HasBattery() { + return input.get("Battery") != null; + } + + public Future ReadBattery() throws ButtplugDeviceFeatureException { + CheckInput("Battery"); + return device.sendInputCommand(featureIndex, "Battery", InputCommandType.READ); + } + + public boolean HasRssi() { + return input.get("Rssi") != null; + } + + public Future ReadRssi() throws ButtplugDeviceFeatureException { + CheckInput("Rssi"); + return device.sendInputCommand(featureIndex, "Rssi", InputCommandType.READ); + } + public String getDescription() { return description; } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java index 7545ab5..7ee4176 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java @@ -243,7 +243,7 @@ public boolean equals(Object o) { @JsonSubTypes.Type(value = DeviceFeature.PositionInput.class, name = "Position") }) public static class InputDescriptor { - @JsonProperty(value = "InputCommandType", required = true) + @JsonProperty(value = "InputCommands", required = true) private ArrayList input; public InputDescriptor(ArrayList input) { diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java index 86d8f79..b6ffba8 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java @@ -6,7 +6,7 @@ public class InputCmd extends ButtplugDeviceMessage { @JsonProperty(value = "FeatureIndex", required = true) - private long featureIndex; + private int featureIndex; @JsonProperty(value = "InputType", required = true) private String inputType; @@ -14,7 +14,7 @@ public class InputCmd extends ButtplugDeviceMessage { @JsonProperty(value = "InputCommand", required = true) private InputCommandType inputCommand; - public InputCmd(int id, final long deviceIndex, final long featureIndex, final String inputType, final InputCommandType inputCommand) { + public InputCmd(int id, final long deviceIndex, final int featureIndex, final String inputType, final InputCommandType inputCommand) { super(id, deviceIndex); this.featureIndex = featureIndex; this.inputType = inputType; @@ -29,11 +29,11 @@ public InputCmd() { } - public long getFeatureIndex() { + public int getFeatureIndex() { return featureIndex; } - public void setFeatureIndex(long featureIndex) { + public void setFeatureIndex(int featureIndex) { this.featureIndex = featureIndex; } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java index 880a28e..ad0846e 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java @@ -15,23 +15,47 @@ public InputReading(int id, long deviceIndex, int featureIndex) { this.featureIndex = featureIndex; } + public InputData getData() { + return data; + } + + public void setData(InputData data) { + this.data = data; + } + + public int getFeatureIndex() { + return featureIndex; + } + + public void setFeatureIndex(int featureIndex) { + this.featureIndex = featureIndex; + } + public interface InputData { } static public class InputIntegerData { @JsonProperty(value = "Data", required = true) int value; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } } - static public class BatteryData implements InputData { + static public class BatteryData extends InputIntegerData { } - static public class RssiData implements InputData { + static public class RssiData extends InputIntegerData { } - static public class ButtonData implements InputData { + static public class ButtonData extends InputIntegerData { } - static public class PresureData implements InputData { + static public class PresureData extends InputIntegerData { } } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java index 40c118f..6e6de43 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfo.java @@ -6,11 +6,11 @@ public final class ServerInfo extends ButtplugMessage { - @JsonProperty(value = "ProtocolMajorVersion", required = true) - private int protocolMajorVersion; + @JsonProperty(value = "ProtocolVersionMajor", required = true) + private int protocolVersionMajor; - @JsonProperty(value = "ProtocolMinorVersion", required = true) - private int protocolMinorVersion; + @JsonProperty(value = "ProtocolVersionMinor", required = true) + private int protocolVersionMinor; @JsonProperty(value = "MaxPingTime", required = true) private long maxPingTime; @@ -18,12 +18,12 @@ public final class ServerInfo extends ButtplugMessage { @JsonProperty(value = "ServerName", required = true) private String serverName; - public ServerInfo(final String serverName, final int protocolMajorVersion, final int protocolMinorVersion, final long maxPingTime, final int id) { + public ServerInfo(final String serverName, final int protocolVersionMajor, final int protocolVersionMinor, final long maxPingTime, final int id) { super(id); this.serverName = serverName; - this.protocolMajorVersion = protocolMajorVersion; - this.protocolMinorVersion = protocolMinorVersion; + this.protocolVersionMajor = protocolVersionMajor; + this.protocolVersionMinor = protocolVersionMinor; this.maxPingTime = maxPingTime; } @@ -32,25 +32,25 @@ private ServerInfo() { super(ButtplugConsts.DEFAULT_MSG_ID); this.serverName = ""; - this.protocolMajorVersion = 4; - this.protocolMinorVersion = 0; + this.protocolVersionMajor = 4; + this.protocolVersionMinor = 0; this.maxPingTime = 0; } - public int getProtocolMajorVersion() { - return protocolMajorVersion; + public int getProtocolVersionMajor() { + return protocolVersionMajor; } - public void setProtocolMajorVersion(final int protocolMajorVersion) { - this.protocolMajorVersion = protocolMajorVersion; + public void setProtocolVersionMajor(final int protocolVersionMajor) { + this.protocolVersionMajor = protocolVersionMajor; } - public int getProtocolMinorVersion() { - return protocolMinorVersion; + public int getProtocolVersionMinor() { + return protocolVersionMinor; } - public void setProtocolMinorVersion(final int protocolMinorVersion) { - this.protocolMinorVersion = protocolMinorVersion; + public void setProtocolVersionMinor(final int protocolVersionMinor) { + this.protocolVersionMinor = protocolVersionMinor; } public long getMaxPingTime() { diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java deleted file mode 100644 index 91562a5..0000000 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/InputReadingTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.blackspherefollower.buttplug4j.protocol.messages; - -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugDeviceMessage; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugJsonMessageParser; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugProtocolException; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -public class InputReadingTest { - - @Test - public void testInputReadingCreation() { - InputReading reading = new InputReading(1, 0, 0); - - assertEquals(1, reading.getId()); - assertEquals(0, reading.getDeviceIndex()); - assertNotNull(reading); - } - - @Test - public void testInputReadingInheritance() { - InputReading reading = new InputReading(1, 0, 0); - - assertInstanceOf(ButtplugDeviceMessage.class, reading); - } - - @Test - public void testInputDataInterfaces() { - // Test that InputData interface classes exist - InputReading.BatteryData batteryData = new InputReading.BatteryData(); - InputReading.RssiData rssiData = new InputReading.RssiData(); - InputReading.ButtonData buttonData = new InputReading.ButtonData(); - InputReading.PresureData presureData = new InputReading.PresureData(); - - assertInstanceOf(InputReading.InputData.class, batteryData); - assertInstanceOf(InputReading.InputData.class, rssiData); - assertInstanceOf(InputReading.InputData.class, buttonData); - assertInstanceOf(InputReading.InputData.class, presureData); - } -} diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java index a9275c1..f42a29f 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java @@ -33,7 +33,7 @@ public static void setup() throws IOException { @Test public void test() throws IOException, ButtplugProtocolException { - String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"InputCommandType\":[\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Position\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"InputCommandType\":[\"Subscribe\",\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"InputCommandType\":[\"Read\"],\"ValueRange\":[[-10,0],[-100,0]]}}}}}}}}]"; + String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"InputCommands\":[\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Position\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"InputCommands\":[\"Subscribe\",\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"InputCommands\":[\"Read\"],\"ValueRange\":[[-10,0],[-100,0]]}}}}}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java index 213a043..e390ebf 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ServerInfoTest.java @@ -34,7 +34,7 @@ public static void setup() throws IOException { @Test public void test() throws IOException, ButtplugProtocolException { - String testStr = "[{\"ServerInfo\":{\"Id\":1,\"ProtocolMajorVersion\":4,\"ProtocolMinorVersion\":0,\"MaxPingTime\":500,\"ServerName\":\"Websocket Server\"}}]"; + String testStr = "[{\"ServerInfo\":{\"Id\":1,\"ProtocolVersionMajor\":4,\"ProtocolVersionMinor\":0,\"MaxPingTime\":500,\"ServerName\":\"Websocket Server\"}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(Error::getError).collect(Collectors.joining("\n"))); @@ -45,8 +45,8 @@ public void test() throws IOException, ButtplugProtocolException { assertEquals(1, msgs.size()); assertEquals(ServerInfo.class, msgs.get(0).getClass()); assertEquals(1, msgs.get(0).getId(), 1); - assertEquals(4, ((ServerInfo) msgs.get(0)).getProtocolMajorVersion()); - assertEquals(0, ((ServerInfo) msgs.get(0)).getProtocolMinorVersion()); + assertEquals(4, ((ServerInfo) msgs.get(0)).getProtocolVersionMajor()); + assertEquals(0, ((ServerInfo) msgs.get(0)).getProtocolVersionMinor()); assertEquals(500, ((ServerInfo) msgs.get(0)).getMaxPingTime()); assertEquals("Websocket Server", ((ServerInfo) msgs.get(0)).getServerName()); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java index c0bc13b..1cee321 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/TestConstants.java @@ -1,5 +1,5 @@ package io.github.blackspherefollower.buttplug4j.protocol.messages; public class TestConstants { - static public final String SCHEMA_URL = "https://raw.githubusercontent.com/buttplugio/buttplug/refs/heads/master/crates/buttplug_core/schema/buttplug-schema.json"; + static public final String SCHEMA_URL = "https://raw.githubusercontent.com/buttplugio/buttplug/refs/heads/dev/crates/buttplug_core/schema/buttplug-schema.json"; } From c50446dd4bfa5a73db2d1ef9b2620403bb0fe7e1 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Wed, 3 Dec 2025 10:56:29 +0000 Subject: [PATCH 3/9] test: Fixing up integration tests --- .../ButtplugClientWSJettyClientTest.java | 7 +- buttplug4j.utils.test/build.gradle | 4 +- .../buttplug4j/utils/test/WSDMClient.java | 122 +++++++++--------- 3 files changed, 67 insertions(+), 66 deletions(-) diff --git a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java index 8595068..1bf6c6a 100644 --- a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java +++ b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java @@ -42,12 +42,13 @@ public void TestConnect() throws Exception { } } } - assertEquals(wsdev.messages.poll(), "DeviceType;"); - assertEquals(wsdev.messages.poll(), "Vibrate:10;"); Thread.sleep(500); + assertEquals("Vibrate:10;", wsdev.messages.poll()); + assertTrue(client.stopAllDevices()); - assertEquals(wsdev.messages.poll(), "Vibrate:0;"); + Thread.sleep(500); + assertEquals("Vibrate:0;", wsdev.messages.poll()); client.disconnect(); } diff --git a/buttplug4j.utils.test/build.gradle b/buttplug4j.utils.test/build.gradle index 076e0d4..b98272d 100644 --- a/buttplug4j.utils.test/build.gradle +++ b/buttplug4j.utils.test/build.gradle @@ -12,14 +12,12 @@ repositories { dependencies { api project(":buttplug4j") - api 'org.eclipse.jetty.websocket:websocket-client:9.4.58.v20250814' - api 'org.eclipse.jetty.websocket:websocket-api:9.4.58.v20250814' api 'org.junit.jupiter:junit-jupiter:5.13.4' } java { toolchain { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(11) } withJavadocJar() withSourcesJar() diff --git a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java index 2c0836b..8169d77 100644 --- a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java +++ b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java @@ -3,36 +3,25 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import io.github.blackspherefollower.buttplug4j.client.ButtplugClient; -import io.github.blackspherefollower.buttplug4j.client.IConnectedEvent; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugConsts; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; -import io.github.blackspherefollower.buttplug4j.protocol.ButtplugProtocolException; -import io.github.blackspherefollower.buttplug4j.protocol.messages.Error; -import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.annotations.*; -import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; -import org.eclipse.jetty.websocket.client.WebSocketClient; import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.WebSocket; import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.*; -@WebSocket(maxTextMessageSize = 64 * 1024) public class WSDMClient { - private WebSocketClient client; - private Session session; - private WSDHeader header; + private WebSocket client; + private final WSDHeader header; public ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); - private CompletableFuture connected = new CompletableFuture<>(); + private final CompletableFuture connected = new CompletableFuture<>(); public int battery = 100; - class WSDHeader { + static class WSDHeader { @JsonProperty("identifier") public String identifier; @JsonProperty("address") @@ -45,64 +34,82 @@ public WSDMClient(final URI url, final String identifier, final String address) header = new WSDHeader(); header.identifier = identifier; header.address = address; - client = new WebSocketClient(); - client.start(); - client.connect(this, url, new ClientUpgradeRequest()).get(2, TimeUnit.SECONDS); - connected.get(5, TimeUnit.SECONDS); + HttpClient + .newHttpClient() + .newWebSocketBuilder() + .buildAsync(url, new WebSocketClient(this)) + .join(); + connected.get(10, TimeUnit.SECONDS); + } - protected void cleanup() { + private static class WebSocketClient implements WebSocket.Listener { + WSDMClient wsdmclient; + public WebSocketClient(WSDMClient wsdmclient) {this.wsdmclient = wsdmclient;} - if (session != null) { - session.close(); - } + @Override + public void onOpen(WebSocket webSocket) { + System.out.println("onOpen using subprotocol " + webSocket.getSubprotocol()); + wsdmclient.onConnect(webSocket); + WebSocket.Listener.super.onOpen(webSocket); + } - try { - LifeCycle.stop(client); - } catch (RuntimeException ignored) { - } - client = null; + @Override + public CompletionStage onText(WebSocket webSocket, CharSequence data, boolean last) { + System.out.println("onText received " + data); + wsdmclient.onMessage(data.toString()); + return WebSocket.Listener.super.onText(webSocket, data, last); } - @OnWebSocketClose - public void onClose(int statusCode, String reason) { - this.session = null; - cleanup(); + @Override + public void onError(WebSocket webSocket, Throwable error) { + System.out.println("Bad day! " + webSocket.toString()); + error.printStackTrace(); + WebSocket.Listener.super.onError(webSocket, error); } - @OnWebSocketConnect - public void onConnect(Session session) { - this.session = session; + @Override + public CompletionStage onClose(WebSocket webSocket, int statusCode, String reason) { + System.out.println("onClose received " + statusCode + " " + reason); + wsdmclient.onClose(statusCode, reason); + return WebSocket.Listener.super.onClose(webSocket, statusCode, reason); + } + + @Override + public CompletionStage onBinary(WebSocket webSocket, ByteBuffer message, boolean last) { + System.out.println("onBinary received " + message); + wsdmclient.onMessage(StandardCharsets.UTF_8.decode(message).toString()); + return WebSocket.Listener.super.onBinary(webSocket, message, last); + } + } + + public void onClose(int statusCode, String reason) { + this.client = null; + } + + public void onConnect(WebSocket client) { + this.client = client; // Don't block the WS thread new Thread(() -> { try { - session.getRemote().sendStringByFuture(new ObjectMapper().writeValueAsString(header)).get(1, TimeUnit.SECONDS); + client.sendText(new ObjectMapper().writeValueAsString(header), true).get(1, TimeUnit.SECONDS); } catch (JsonProcessingException | ExecutionException | InterruptedException |TimeoutException e) { System.out.println("Failed to send header: " + e.getMessage()); } }).start(); } - @OnWebSocketFrame - public void onFrame(final Frame frame) { - if( frame.getType().isData()) { - System.out.println("Got frame: " + frame); - byte[] data = new byte[frame.getPayloadLength()]; - frame.getPayload().get(data); - onMessage(null, new String(data, StandardCharsets.UTF_8)); - } - } - - @OnWebSocketMessage - public void onMessage(final Session sess, final String message) { + public void onMessage(final String message) { System.out.println("Got message: " + message); if(message.startsWith("DeviceType;")) { new Thread(() -> { try { - session.getRemote().sendBytesByFuture(ByteBuffer.wrap(("Z:10:" + header.address + ";").getBytes(StandardCharsets.UTF_8))).get(1, TimeUnit.SECONDS); - connected.complete(true); + sendMessage("Z:10:" + header.address + ";"); + if(!connected.isDone()) { + connected.complete(true); + } } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new RuntimeException(e); } @@ -113,7 +120,7 @@ public void onMessage(final Session sess, final String message) { if(message.startsWith("Battery;")) { new Thread(() -> { try { - session.getRemote().sendBytesByFuture(ByteBuffer.wrap((battery + ";").getBytes(StandardCharsets.UTF_8))).get(1, TimeUnit.SECONDS); + sendMessage(battery + ";"); connected.complete(true); } catch (InterruptedException | ExecutionException | TimeoutException e) { throw new RuntimeException(e); @@ -125,12 +132,7 @@ public void onMessage(final Session sess, final String message) { messages.add(message); } - @OnWebSocketError - public void onWebSocketError(final Throwable cause) { - System.out.println("Got error: " + cause.getMessage()); - } - protected void sendMessage(final String msg) throws ExecutionException, InterruptedException, TimeoutException { - session.getRemote().sendStringByFuture(msg).get(1, TimeUnit.SECONDS); + client.sendBinary(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)), true).get(1, TimeUnit.SECONDS); } } From 71566e79404dcf1a09acc10a32bbc06aa7c19eb8 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Fri, 5 Dec 2025 11:16:50 +0000 Subject: [PATCH 4/9] chore: Code cleanup --- .../client/ButtplugWSClientMockTest.java | 6 +- .../ButtplugClientWSServerMockTest.java | 11 +- .../ButtplugClientWSJettyClientTest.java | 11 +- buttplug4j.utils.mdns/build.gradle | 1 + .../utils/mdns/ButtplugDiscover.java | 37 ++++- .../utils/mdns/ButtplugDiscoverTest.java | 51 ++++-- .../utils/test/IntifaceEngineWrapper.java | 33 ++-- .../buttplug4j/utils/test/WSDMClient.java | 156 +++++++++--------- .../client/ButtplugClientDeviceFeature.java | 1 - .../buttplug4j/util/Pair.java | 2 +- .../buttplug4j/ButtplugExceptionTest.java | 6 +- .../ButtplugClientDeviceFeatureTest.java | 93 ++++++----- .../client/ButtplugClientDeviceTest.java | 65 ++++---- .../client/ButtplugClientExceptionTest.java | 6 +- .../buttplug4j/client/ButtplugClientTest.java | 40 ++--- .../client/ButtplugDeviceExceptionTest.java | 6 +- .../ButtplugDeviceFeatureExceptionTest.java | 6 +- .../client/ButtplugProtocolExceptionTest.java | 6 +- .../buttplug4j/client/DeviceFeatureTest.java | 4 +- .../protocol/ButtplugMessageTest.java | 5 +- .../protocol/messages/DeviceListTest.java | 2 +- .../protocol/messages/InputCmdTest.java | 3 +- .../protocol/messages/InputReadingTest.java | 2 +- .../protocol/messages/OutputCmdTest.java | 22 +-- .../buttplug4j/util/PairTest.java | 17 +- 25 files changed, 327 insertions(+), 265 deletions(-) diff --git a/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java b/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java index fb1e0b6..3b4ba51 100644 --- a/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java +++ b/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java @@ -5,8 +5,8 @@ import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceFeatureException; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; import io.github.blackspherefollower.buttplug4j.protocol.messages.InputReading; -import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient; import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper; +import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -18,7 +18,7 @@ public class ButtplugWSClientMockTest { @Test public void TestConnect() throws Exception { - try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { + try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) { Thread.sleep(500); WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); Thread.sleep(500); @@ -51,7 +51,7 @@ public void TestConnect() throws Exception { @Test @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void TestBattery() throws Exception { - try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { + try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) { Thread.sleep(500); WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); Thread.sleep(500); diff --git a/buttplug4j.connectors.javax.websocket.server/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/server/ButtplugClientWSServerMockTest.java b/buttplug4j.connectors.javax.websocket.server/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/server/ButtplugClientWSServerMockTest.java index 5ecc96b..5d00578 100644 --- a/buttplug4j.connectors.javax.websocket.server/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/server/ButtplugClientWSServerMockTest.java +++ b/buttplug4j.connectors.javax.websocket.server/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/server/ButtplugClientWSServerMockTest.java @@ -11,14 +11,13 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import javax.websocket.Session; import javax.websocket.server.ServerEndpointConfig; -import java.io.IOException; import java.net.URI; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -32,7 +31,7 @@ public void TestConnect() throws Exception { ButtplugClientWSServerExample server = new ButtplugClientWSServerExample(lport, testDone); Thread.sleep(500); - try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper(lport) ) { + try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper(lport)) { Thread.sleep(500); WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); testDone.get(10, TimeUnit.SECONDS); @@ -90,8 +89,8 @@ public void onConnected(ButtplugClient client) { firstDevice.get(5, TimeUnit.SECONDS); for (ButtplugClientDevice dev : client.getDevices()) { - for(ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { - if( feat.HasVibrate() ) { + for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { + if (feat.HasVibrate()) { feat.VibrateFloat(0.5F).get(); } } diff --git a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java index 1bf6c6a..2b37ebf 100644 --- a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java +++ b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java @@ -3,16 +3,13 @@ import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDevice; import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDeviceFeature; import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceFeatureException; -import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient; -import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; import io.github.blackspherefollower.buttplug4j.protocol.messages.InputReading; - +import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper; +import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.IOException; import java.net.URI; import static org.junit.jupiter.api.Assertions.*; @@ -22,7 +19,7 @@ public class ButtplugClientWSJettyClientTest { @Test public void TestConnect() throws Exception { - try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { + try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) { Thread.sleep(500); WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); Thread.sleep(500); @@ -57,7 +54,7 @@ public void TestConnect() throws Exception { @Test @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void TestBattery() throws Exception { - try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) { + try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) { Thread.sleep(500); WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B"); Thread.sleep(500); diff --git a/buttplug4j.utils.mdns/build.gradle b/buttplug4j.utils.mdns/build.gradle index f3116dd..ae08bf6 100644 --- a/buttplug4j.utils.mdns/build.gradle +++ b/buttplug4j.utils.mdns/build.gradle @@ -14,6 +14,7 @@ dependencies { api 'org.jmdns:jmdns:3.6.1' api 'org.slf4j:slf4j-simple:2.0.17' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' + testImplementation project(':buttplug4j.utils.test') testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' } diff --git a/buttplug4j.utils.mdns/src/main/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscover.java b/buttplug4j.utils.mdns/src/main/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscover.java index 0dbbec5..2e9c255 100644 --- a/buttplug4j.utils.mdns/src/main/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscover.java +++ b/buttplug4j.utils.mdns/src/main/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscover.java @@ -3,6 +3,9 @@ import javax.jmdns.JmmDNS; import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceListener; +import javax.jmdns.ServiceTypeListener; +import java.io.Closeable; +import java.io.IOException; import java.net.Inet4Address; import java.net.URI; import java.net.URISyntaxException; @@ -10,31 +13,41 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; -public final class ButtplugDiscover implements ServiceListener { +public final class ButtplugDiscover implements ServiceListener, Closeable { private final ConcurrentHashMap> servers = new ConcurrentHashMap<>(); + private final JmmDNS jmmdns; private DiscovereyEventHandler discovereyEventHandler = null; public ButtplugDiscover(DiscovereyEventHandler discovereyEventHandler) { this.discovereyEventHandler = discovereyEventHandler; - JmmDNS jmmdns = JmmDNS.Factory.getInstance(); + jmmdns = JmmDNS.Factory.getInstance(); jmmdns.addServiceListener("_intiface_engine._tcp.local.", this); - } + try { + jmmdns.addServiceTypeListener(new ServiceTypeListener() { + @Override + public void serviceTypeAdded(ServiceEvent serviceEvent) { + System.err.println("Added service type " + serviceEvent.getType()); + } - public ButtplugDiscover() { - JmmDNS jmmdns = JmmDNS.Factory.getInstance(); - jmmdns.addServiceListener("_intiface_engine._tcp.local.", this); - } + @Override + public void subTypeForServiceTypeAdded(ServiceEvent serviceEvent) { + System.err.println("Added sub type " + serviceEvent.getType()); - public void setDiscovereyEventHandler(DiscovereyEventHandler discovereyEventHandler) { - this.discovereyEventHandler = discovereyEventHandler; + } + }); + } catch (IOException e) { + e.printStackTrace(); + } } @Override public void serviceAdded(ServiceEvent event) { + System.err.println("Added " + event.getName() + " " + event.getInfo().toString() + " " + event.getType()); } @Override public void serviceRemoved(ServiceEvent event) { + System.err.println("Removed " + event.getName() + " " + event.getInfo().toString() + " " + event.getType()); servers.remove(event.getInfo().getName()); if (discovereyEventHandler != null) { discovereyEventHandler.LostButtplug(event.getInfo().getName()); @@ -43,6 +56,7 @@ public void serviceRemoved(ServiceEvent event) { @Override public void serviceResolved(ServiceEvent event) { + System.err.println("Resolved " + event.getName() + " " + event.getInfo().toString() + " " + event.getType()); ConcurrentSkipListSet set = new ConcurrentSkipListSet<>(); for (Inet4Address addr : event.getInfo().getInet4Addresses()) { @@ -68,6 +82,11 @@ public ConcurrentHashMap> GetServers() { return servers; } + @Override + public void close() throws IOException { + jmmdns.close(); + } + public interface DiscovereyEventHandler { void FoundButtplug(String name, Set addresses); diff --git a/buttplug4j.utils.mdns/src/test/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscoverTest.java b/buttplug4j.utils.mdns/src/test/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscoverTest.java index 8c9420f..a36f14a 100644 --- a/buttplug4j.utils.mdns/src/test/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscoverTest.java +++ b/buttplug4j.utils.mdns/src/test/java/io/github/blackspherefollower/buttplug4j/utils/mdns/ButtplugDiscoverTest.java @@ -1,30 +1,57 @@ package io.github.blackspherefollower.buttplug4j.utils.mdns; +import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ButtplugDiscoverTest { - @Disabled + @Disabled("Not able to get mDNS this working right now") @Test public void TestConnect() throws Exception { - ButtplugDiscover discover = new ButtplugDiscover(new ButtplugDiscover.DiscovereyEventHandler() { - @Override - public void FoundButtplug(String name, Set addresses) { - System.out.println("WOO, a buttplug appeared : " + name + " : " + String.join(", ", addresses.stream().map(uri -> uri.toString()).collect(Collectors.toList()))); - } + CompletableFuture seen1 = new CompletableFuture<>(); + CompletableFuture seen2 = new CompletableFuture<>(); + CompletableFuture gone1 = new CompletableFuture<>(); + CompletableFuture gone2 = new CompletableFuture<>(); + try ( + IntifaceEngineWrapper wrapper1 = new IntifaceEngineWrapper(new ArrayList<>(Arrays.asList("--broadcast-server-mdns"))); + IntifaceEngineWrapper wrapper2 = new IntifaceEngineWrapper(new ArrayList<>(Arrays.asList("--broadcast-server-mdns", "--mdns-suffix", "test-intiface-2"))); + + ButtplugDiscover discover = new ButtplugDiscover(new ButtplugDiscover.DiscovereyEventHandler() { + @Override + public void FoundButtplug(String name, Set addresses) { + System.out.println("WOO, a buttplug appeared : " + name + " : " + String.join(", ", addresses.stream().map(uri -> uri.toString()).collect(Collectors.toList()))); + } + + @Override + public void LostButtplug(String name) { + System.out.println("Oh... a buttplug disappeared : " + name); + } + }); + ) { + + assertTrue(seen1.get(2, TimeUnit.MINUTES)); + assertTrue(seen2.get(15, TimeUnit.SECONDS)); - @Override - public void LostButtplug(String name) { - System.out.println("Oh... a buttplug disappeared : " + name); - } - }); + assertFalse(gone1.isDone()); + wrapper1.close(); + assertTrue(gone1.get(15, TimeUnit.SECONDS)); - Thread.sleep(60000); + assertFalse(gone2.isDone()); + wrapper2.close(); + assertTrue(gone2.get(15, TimeUnit.SECONDS)); + } } } \ No newline at end of file diff --git a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java index 3172aa2..11fa861 100644 --- a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java +++ b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java @@ -3,6 +3,8 @@ import java.io.*; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; public class IntifaceEngineWrapper implements Closeable { @@ -15,20 +17,28 @@ public IntifaceEngineWrapper() throws Exception { cport = (int) (Math.random() * 63000) + 1025; dport = (int) (Math.random() * 63000) + 1025; - setup(true); + setup(true, new ArrayList()); } + public IntifaceEngineWrapper(int lport) throws Exception { cport = lport; dport = (int) (Math.random() * 63000) + 1025; - setup(false); + setup(false, new ArrayList()); + } + + public IntifaceEngineWrapper(ArrayList extraArgs) throws Exception { + cport = (int) (Math.random() * 63000) + 1025; + dport = (int) (Math.random() * 63000) + 1025; + + setup(true, extraArgs); } - public void setup(boolean listen) throws Exception { - try{ + public void setup(boolean listen, ArrayList extraArgs) throws Exception { + try { Runtime.getRuntime().exec("intiface-engine --version").waitFor(); } catch (IOException e) { - org.junit.jupiter.api.Assumptions.abort( "intiface-engine not found, skipping tests"); + org.junit.jupiter.api.Assumptions.abort("intiface-engine not found, skipping tests"); } Path userConfig = Files.createTempFile("user-config_", ".json"); @@ -46,8 +56,9 @@ public void setup(boolean listen) throws Exception { } } - ProcessBuilder pb = - new ProcessBuilder("intiface-engine", listen ? "--websocket-port" : "--websocket-client-address", listen ? String.valueOf(cport) : ("ws://127.0.0.1:" + String.valueOf(cport) + "/bob"), "--use-device-websocket-server", "--user-device-config-file", userConfig.toAbsolutePath().toString(), "--device-websocket-server-port", String.valueOf(dport), "--log", "TRACE"); + ArrayList args = new ArrayList<>(Arrays.asList("intiface-engine", listen ? "--websocket-port" : "--websocket-client-address", listen ? String.valueOf(cport) : ("ws://127.0.0.1:" + String.valueOf(cport) + "/bob"), "--use-device-websocket-server", "--user-device-config-file", userConfig.toAbsolutePath().toString(), "--device-websocket-server-port", String.valueOf(dport), "--log", "TRACE")); + args.addAll(extraArgs); + ProcessBuilder pb = new ProcessBuilder(args); Path log = Files.createTempFile("intiface_", ".log"); pb.redirectErrorStream(true); @@ -55,18 +66,18 @@ public void setup(boolean listen) throws Exception { proc = pb.start(); Thread.sleep(500); - if( !proc.isAlive()) { + if (!proc.isAlive()) { close(); - org.junit.jupiter.api.Assumptions.abort( "intiface-engine not started, skipping tests"); + org.junit.jupiter.api.Assumptions.abort("intiface-engine not started, skipping tests"); } } @Override public void close() { - if(proc != null) { + if (proc != null) { proc.destroyForcibly(); } - if(userConfig != null) { + if (userConfig != null) { try { Files.deleteIfExists(userConfig); } catch (IOException ignore) { diff --git a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java index 8169d77..3b5f7f5 100644 --- a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java +++ b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java @@ -8,45 +8,97 @@ import java.net.http.HttpClient; import java.net.http.WebSocket; import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.*; public class WSDMClient { - private WebSocket client; - private final WSDHeader header; - public ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); - private final CompletableFuture connected = new CompletableFuture<>(); + private final WSDHeader header; + private final CompletableFuture connected = new CompletableFuture<>(); + public ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); + public int battery = 100; + private WebSocket client; - public int battery = 100; + public WSDMClient(final URI url, final String identifier, final String address) throws Exception { + header = new WSDHeader(); + header.identifier = identifier; + header.address = address; - static class WSDHeader { - @JsonProperty("identifier") - public String identifier; - @JsonProperty("address") - public String address; - @JsonProperty("version") - public int version = 0; - } + HttpClient + .newHttpClient() + .newWebSocketBuilder() + .buildAsync(url, new WebSocketClient(this)) + .join(); + connected.get(10, TimeUnit.SECONDS); + + } + + public void onClose(int statusCode, String reason) { + this.client = null; + } + + public void onConnect(WebSocket client) { + this.client = client; + // Don't block the WS thread + new Thread(() -> { + try { + client.sendText(new ObjectMapper().writeValueAsString(header), true).get(1, TimeUnit.SECONDS); + } catch (JsonProcessingException | ExecutionException | InterruptedException | TimeoutException e) { + System.out.println("Failed to send header: " + e.getMessage()); + } + }).start(); + } - public WSDMClient(final URI url, final String identifier, final String address) throws Exception { - header = new WSDHeader(); - header.identifier = identifier; - header.address = address; + public void onMessage(final String message) { + System.out.println("Got message: " + message); + if (message.startsWith("DeviceType;")) { + new Thread(() -> { + try { + sendMessage("Z:10:" + header.address + ";"); + if (!connected.isDone()) { + connected.complete(true); + } + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } - HttpClient - .newHttpClient() - .newWebSocketBuilder() - .buildAsync(url, new WebSocketClient(this)) - .join(); - connected.get(10, TimeUnit.SECONDS); + }).start(); + return; + } + if (message.startsWith("Battery;")) { + new Thread(() -> { + try { + sendMessage(battery + ";"); + connected.complete(true); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } + }).start(); + return; } + messages.add(message); + } + + protected void sendMessage(final String msg) throws ExecutionException, InterruptedException, TimeoutException { + client.sendBinary(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)), true).get(1, TimeUnit.SECONDS); + } + + static class WSDHeader { + @JsonProperty("identifier") + public String identifier; + @JsonProperty("address") + public String address; + @JsonProperty("version") + public int version = 0; + } private static class WebSocketClient implements WebSocket.Listener { WSDMClient wsdmclient; - public WebSocketClient(WSDMClient wsdmclient) {this.wsdmclient = wsdmclient;} + + public WebSocketClient(WSDMClient wsdmclient) { + this.wsdmclient = wsdmclient; + } @Override public void onOpen(WebSocket webSocket) { @@ -83,56 +135,4 @@ public CompletionStage onBinary(WebSocket webSocket, ByteBuffer message, bool return WebSocket.Listener.super.onBinary(webSocket, message, last); } } - - - public void onClose(int statusCode, String reason) { - this.client = null; - } - - public void onConnect(WebSocket client) { - this.client = client; - // Don't block the WS thread - new Thread(() -> { - try { - client.sendText(new ObjectMapper().writeValueAsString(header), true).get(1, TimeUnit.SECONDS); - } catch (JsonProcessingException | ExecutionException | InterruptedException |TimeoutException e) { - System.out.println("Failed to send header: " + e.getMessage()); - } - }).start(); - } - - public void onMessage(final String message) { - System.out.println("Got message: " + message); - if(message.startsWith("DeviceType;")) { - new Thread(() -> { - try { - sendMessage("Z:10:" + header.address + ";"); - if(!connected.isDone()) { - connected.complete(true); - } - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new RuntimeException(e); - } - - }).start(); - return; - } - if(message.startsWith("Battery;")) { - new Thread(() -> { - try { - sendMessage(battery + ";"); - connected.complete(true); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new RuntimeException(e); - } - - }).start(); - return; - } - messages.add(message); - } - - protected void sendMessage(final String msg) throws ExecutionException, InterruptedException, TimeoutException { - client.sendBinary(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)), true).get(1, TimeUnit.SECONDS); - } - } +} diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java index 119e414..5072ef1 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java @@ -2,7 +2,6 @@ import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; import io.github.blackspherefollower.buttplug4j.protocol.messages.DeviceFeature; -import io.github.blackspherefollower.buttplug4j.protocol.messages.InputCmd; import io.github.blackspherefollower.buttplug4j.protocol.messages.InputCommandType; import io.github.blackspherefollower.buttplug4j.protocol.messages.OutputCmd; diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/util/Pair.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/util/Pair.java index c2e3b8d..d528247 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/util/Pair.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/util/Pair.java @@ -43,7 +43,7 @@ public boolean equals(Object o) { } return ((Pair) o).a.equals(a) && ((Pair) o).b.equals(b); } - + @Override public int hashCode() { return a.hashCode() ^ b.hashCode(); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/ButtplugExceptionTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/ButtplugExceptionTest.java index fac4ec2..2343ba3 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/ButtplugExceptionTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/ButtplugExceptionTest.java @@ -1,8 +1,8 @@ - package io.github.blackspherefollower.buttplug4j; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ButtplugExceptionTest { @@ -11,7 +11,7 @@ public void testExceptionWithMessage() { String errorMessage = "Test error message"; ButtplugException exception = new ButtplugException(); exception.setMessage(errorMessage); - + assertEquals(errorMessage, exception.getMessage()); } } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java index 6625a2a..e2165a7 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java @@ -1,4 +1,3 @@ - package io.github.blackspherefollower.buttplug4j.client; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; @@ -25,12 +24,12 @@ class ButtplugClientDeviceFeatureTest { @BeforeEach void setup() { mockDevice = mock(ButtplugClientDevice.class); - + // Create a test feature with various output types testFeature = new DeviceFeature(); testFeature.setFeatureIndex(0); testFeature.setFeatureDescription("Test Feature"); - + ArrayList outputs = new ArrayList<>(); outputs.add(new DeviceFeature.Vibrate(new int[]{0, 100})); outputs.add(new DeviceFeature.Rotate(new int[]{0, 50})); @@ -41,10 +40,10 @@ void setup() { outputs.add(new DeviceFeature.Led(new int[]{0, 255})); outputs.add(new DeviceFeature.Temperature(new int[]{0, 30})); testFeature.setOutput(outputs); - + ArrayList inputs = new ArrayList<>(); testFeature.setInput(inputs); - + clientFeature = new ButtplugClientDeviceFeature(mockDevice, testFeature); } @@ -57,9 +56,9 @@ void testConstructor() { void testVibrateWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Vibrate(50); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -77,9 +76,9 @@ void testVibrateWithInvalidStepThrowsException() { void testVibrateFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.VibrateFloat(0.5f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -91,13 +90,13 @@ void testVibrateFloatWithValidValue() throws Exception { void testVibrateFloatWithBoundaryValues() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + // Test minimum value clientFeature.VibrateFloat(0.0f); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); assertEquals(0, ((OutputCmd.Vibrate) captor.getValue()).getValue()); - + // Test maximum value reset(mockDevice); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); @@ -116,9 +115,9 @@ void testVibrateFloatWithInvalidValueThrowsException() { void testRotateWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Rotate(25); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -130,9 +129,9 @@ void testRotateWithValidStep() throws Exception { void testRotateFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.RotateFloat(0.5f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -144,9 +143,9 @@ void testRotateFloatWithValidValue() throws Exception { void testConstrictWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Constrict(5); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -158,9 +157,9 @@ void testConstrictWithValidStep() throws Exception { void testConstrictFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.ConstrictFloat(0.5f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -172,9 +171,9 @@ void testConstrictFloatWithValidValue() throws Exception { void testSprayWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Spray(3); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -186,9 +185,9 @@ void testSprayWithValidStep() throws Exception { void testSprayFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.SprayFloat(0.6f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -200,9 +199,9 @@ void testSprayFloatWithValidValue() throws Exception { void testPositionWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Position(15); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -214,9 +213,9 @@ void testPositionWithValidStep() throws Exception { void testPositionFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.PositionFloat(0.8f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -228,13 +227,13 @@ void testPositionFloatWithValidValue() throws Exception { void testPositionWithDurationWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + // Add PositionWithDuration to the feature testFeature.getOutput().add(new DeviceFeature.PositionWithDuration(new int[]{0, 25}, new int[]{0, 1000})); clientFeature = new ButtplugClientDeviceFeature(mockDevice, testFeature); - + Future result = clientFeature.PositionWithDuration(15, 500); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -247,13 +246,13 @@ void testPositionWithDurationWithValidStep() throws Exception { void testPositionWithDurationFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + // Add PositionWithDuration to the feature testFeature.getOutput().add(new DeviceFeature.PositionWithDuration(new int[]{0, 25}, new int[]{0, 1000})); clientFeature = new ButtplugClientDeviceFeature(mockDevice, testFeature); - + Future result = clientFeature.PositionWithDurationFloat(0.8f, 500); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -266,9 +265,9 @@ void testPositionWithDurationFloatWithValidValue() throws Exception { void testLedWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Led(128); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -280,9 +279,9 @@ void testLedWithValidStep() throws Exception { void testLedFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.LedFloat(0.5f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -294,9 +293,9 @@ void testLedFloatWithValidValue() throws Exception { void testOscillateWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Oscillate(10); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -308,9 +307,9 @@ void testOscillateWithValidStep() throws Exception { void testOscillateFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.OscillateFloat(0.5f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -322,9 +321,9 @@ void testOscillateFloatWithValidValue() throws Exception { void testTemperatureWithValidStep() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.Temperature(15); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -336,9 +335,9 @@ void testTemperatureWithValidStep() throws Exception { void testTemperatureFloatWithValidValue() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(mock(ButtplugMessage.class)); when(mockDevice.sendOutputCommand(anyInt(), any(OutputCmd.IOutputCommand.class))).thenReturn(future); - + Future result = clientFeature.TemperatureFloat(0.5f); - + assertNotNull(result); ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); @@ -354,9 +353,9 @@ void testUnsupportedOutputTypeThrowsException() { limitedFeature.setFeatureDescription("Limited Feature"); limitedFeature.setOutput(new ArrayList<>()); limitedFeature.setInput(new ArrayList<>()); - + ButtplugClientDeviceFeature limited = new ButtplugClientDeviceFeature(mockDevice, limitedFeature); - + assertThrows(ButtplugDeviceFeatureException.class, () -> limited.Vibrate(50)); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceTest.java index 46f0f52..0856f47 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceTest.java @@ -1,4 +1,3 @@ - package io.github.blackspherefollower.buttplug4j.client; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage; @@ -30,7 +29,7 @@ void setup() { mockClient = mock(ButtplugClient.class); HashMap features = new HashMap<>(); - + // Feature 0: Vibrator DeviceFeature vibratorFeature = new DeviceFeature(); vibratorFeature.setFeatureIndex(0); @@ -39,7 +38,7 @@ void setup() { vibratorOutputs.add(new DeviceFeature.Vibrate(new int[]{0, 100})); vibratorFeature.setOutput(vibratorOutputs); features.put(0, vibratorFeature); - + // Feature 1: Battery sensor DeviceFeature batteryFeature = new DeviceFeature(); batteryFeature.setFeatureIndex(1); @@ -52,14 +51,14 @@ void setup() { features.put(1, batteryFeature); // Create a test device with various features - testDevice = new Device(5, "Test Device",features, 100, "Display Name"); + testDevice = new Device(5, "Test Device", features, 100, "Display Name"); testDevice.setDeviceFeatures(features); - + when(mockClient.getNextMsgId()).thenReturn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); when(mockClient.sendMessage(any(ButtplugMessage.class))) .thenReturn(CompletableFuture.completedFuture(mock(ButtplugMessage.class))); - + clientDevice = new ButtplugClientDevice(mockClient, testDevice); } @@ -75,7 +74,7 @@ void testConstructorInitializesProperties() { void testConstructorWithNullDisplayName() { testDevice.setDeviceDisplayName(null); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals("Test Device", device.getDisplayName()); } @@ -83,14 +82,14 @@ void testConstructorWithNullDisplayName() { void testConstructorWithEmptyDisplayName() { testDevice.setDeviceDisplayName(""); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals("Test Device", device.getDisplayName()); } @Test void testGetDeviceFeatures() { Map features = clientDevice.getDeviceFeatures(); - + assertNotNull(features); assertEquals(2, features.size()); assertTrue(features.containsKey(0)); @@ -102,7 +101,7 @@ void testGetDeviceFeatures() { @Test void testSendStopDeviceCmd() { Future result = clientDevice.sendStopDeviceCmd(); - + assertNotNull(result); verify(mockClient).getNextMsgId(); verify(mockClient).sendMessage(any(ButtplugMessage.class)); @@ -111,9 +110,9 @@ void testSendStopDeviceCmd() { @Test void testSendOutputCommand() { OutputCmd.Vibrate vibrateCommand = new OutputCmd.Vibrate(50); - + Future result = clientDevice.sendOutputCommand(0, vibrateCommand); - + assertNotNull(result); verify(mockClient).getNextMsgId(); verify(mockClient).sendMessage(any(OutputCmd.class)); @@ -122,9 +121,9 @@ void testSendOutputCommand() { @Test void testSendOutputCommandWithDifferentFeatureIndex() { OutputCmd.Vibrate vibrateCommand = new OutputCmd.Vibrate(75); - + Future result = clientDevice.sendOutputCommand(1, vibrateCommand); - + assertNotNull(result); verify(mockClient).getNextMsgId(); verify(mockClient).sendMessage(any(OutputCmd.class)); @@ -134,7 +133,7 @@ void testSendOutputCommandWithDifferentFeatureIndex() { void testDeviceWithNoMessageTimingGap() { testDevice.setDeviceMessageTimingGap(null); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertNull(device.getMessageTimingGap()); } @@ -142,7 +141,7 @@ void testDeviceWithNoMessageTimingGap() { void testDeviceWithZeroMessageTimingGap() { testDevice.setDeviceMessageTimingGap(0); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals(Integer.valueOf(0), device.getMessageTimingGap()); } @@ -150,7 +149,7 @@ void testDeviceWithZeroMessageTimingGap() { void testDeviceWithNoFeatures() { testDevice.setDeviceFeatures(new HashMap<>()); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + Map features = device.getDeviceFeatures(); assertNotNull(features); assertTrue(features.isEmpty()); @@ -160,7 +159,7 @@ void testDeviceWithNoFeatures() { void testDeviceWithNullFeatures() { testDevice.setDeviceFeatures(null); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + Map features = device.getDeviceFeatures(); assertNotNull(features); assertTrue(features.isEmpty()); @@ -169,7 +168,7 @@ void testDeviceWithNullFeatures() { @Test void testDeviceWithMultipleOutputFeatures() { HashMap multiFeatures = new HashMap<>(); - + // Add multiple output features for (int i = 0; i < 5; i++) { DeviceFeature feature = new DeviceFeature(); @@ -180,13 +179,13 @@ void testDeviceWithMultipleOutputFeatures() { feature.setOutput(outputs); multiFeatures.put(i, feature); } - + testDevice.setDeviceFeatures(multiFeatures); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + Map features = device.getDeviceFeatures(); assertEquals(5, features.size()); - + for (int i = 0; i < 5; i++) { assertTrue(features.containsKey(i)); assertEquals("Feature " + i, features.get(i).getDescription()); @@ -196,7 +195,7 @@ void testDeviceWithMultipleOutputFeatures() { @Test void testDeviceWithMixedInputOutputFeatures() { HashMap mixedFeatures = new HashMap<>(); - + // Output feature DeviceFeature outputFeature = new DeviceFeature(); outputFeature.setFeatureIndex(0); @@ -205,7 +204,7 @@ void testDeviceWithMixedInputOutputFeatures() { outputs.add(new DeviceFeature.Rotate(new int[]{0, 50})); outputFeature.setOutput(outputs); mixedFeatures.put(0, outputFeature); - + // Input feature DeviceFeature inputFeature = new DeviceFeature(); inputFeature.setFeatureIndex(1); @@ -216,7 +215,7 @@ void testDeviceWithMixedInputOutputFeatures() { inputs.add(new DeviceFeature.Pressure(commands, new int[][]{{0, 0}, {0, 100}})); inputFeature.setInput(inputs); mixedFeatures.put(1, inputFeature); - + // Both input and output feature DeviceFeature mixedFeature = new DeviceFeature(); mixedFeature.setFeatureIndex(2); @@ -224,10 +223,10 @@ void testDeviceWithMixedInputOutputFeatures() { mixedFeature.setOutput(outputs); mixedFeature.setInput(inputs); mixedFeatures.put(2, mixedFeature); - + testDevice.setDeviceFeatures(mixedFeatures); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + Map features = device.getDeviceFeatures(); assertEquals(3, features.size()); assertEquals("Output Feature", features.get(0).getDescription()); @@ -261,7 +260,7 @@ void testDeviceWithSpecialCharactersInName() { testDevice.setDeviceName(specialName); testDevice.setDeviceDisplayName(specialName); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals(specialName, device.getName()); assertEquals(specialName, device.getDisplayName()); } @@ -270,7 +269,7 @@ void testDeviceWithSpecialCharactersInName() { void testDeviceWithNegativeIndex() { testDevice.setDeviceIndex(-1); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals(-1, device.getDeviceIndex()); } @@ -278,7 +277,7 @@ void testDeviceWithNegativeIndex() { void testDeviceWithLargeIndex() { testDevice.setDeviceIndex(Integer.MAX_VALUE); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals(Integer.MAX_VALUE, device.getDeviceIndex()); } @@ -286,7 +285,7 @@ void testDeviceWithLargeIndex() { void testDeviceWithLargeMessageTimingGap() { testDevice.setDeviceMessageTimingGap(Integer.MAX_VALUE); ButtplugClientDevice device = new ButtplugClientDevice(mockClient, testDevice); - + assertEquals(Integer.valueOf(Integer.MAX_VALUE), device.getMessageTimingGap()); } @@ -295,11 +294,11 @@ void testMultipleSendOutputCommandCalls() { OutputCmd.Vibrate command1 = new OutputCmd.Vibrate(25); OutputCmd.Vibrate command2 = new OutputCmd.Vibrate(50); OutputCmd.Vibrate command3 = new OutputCmd.Vibrate(75); - + Future result1 = clientDevice.sendOutputCommand(0, command1); Future result2 = clientDevice.sendOutputCommand(0, command2); Future result3 = clientDevice.sendOutputCommand(0, command3); - + assertNotNull(result1); assertNotNull(result2); assertNotNull(result3); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientExceptionTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientExceptionTest.java index 6676d42..49eff10 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientExceptionTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientExceptionTest.java @@ -2,7 +2,9 @@ import io.github.blackspherefollower.buttplug4j.ButtplugException; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class ButtplugClientExceptionTest { @@ -10,7 +12,7 @@ public class ButtplugClientExceptionTest { public void testExceptionWithMessage() { String errorMessage = "Client error occurred"; ButtplugClientException exception = new ButtplugClientException(errorMessage); - + assertEquals(errorMessage, exception.getMessage()); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientTest.java index b43aed4..a7faf2a 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientTest.java @@ -171,7 +171,7 @@ void testOnMessageWithInputReading() { @Test void testStartScanningAsync() { CompletableFuture future = (CompletableFuture) client.startScanningAsync(); - + assertNotNull(future); assertInstanceOf(StartScanning.class, client.lastSentMessage); } @@ -179,7 +179,7 @@ void testStartScanningAsync() { @Test void testStopScanningAsync() { CompletableFuture future = (CompletableFuture) client.stopScanningAsync(); - + assertNotNull(future); assertInstanceOf(StopScanning.class, client.lastSentMessage); } @@ -187,7 +187,7 @@ void testStopScanningAsync() { @Test void testStopAllDevicesAsync() { CompletableFuture future = (CompletableFuture) client.stopAllDevicesAsync(); - + assertNotNull(future); assertInstanceOf(StopAllDevices.class, client.lastSentMessage); } @@ -196,7 +196,7 @@ void testStopAllDevicesAsync() { void testStartScanning() throws ExecutionException, InterruptedException, IOException { client.setNextResponse(new Ok(1)); boolean result = client.startScanning(); - + assertTrue(result); assertInstanceOf(StartScanning.class, client.lastSentMessage); } @@ -205,7 +205,7 @@ void testStartScanning() throws ExecutionException, InterruptedException, IOExce void testStopScanning() throws ExecutionException, InterruptedException { client.setNextResponse(new Ok(1)); boolean result = client.stopScanning(); - + assertTrue(result); assertInstanceOf(StopScanning.class, client.lastSentMessage); } @@ -214,7 +214,7 @@ void testStopScanning() throws ExecutionException, InterruptedException { void testStopAllDevices() throws ExecutionException, InterruptedException, IOException { client.setNextResponse(new Ok(1)); boolean result = client.stopAllDevices(); - + assertTrue(result); assertInstanceOf(StopAllDevices.class, client.lastSentMessage); } @@ -222,7 +222,7 @@ void testStopAllDevices() throws ExecutionException, InterruptedException, IOExc @Test void testGetDevicesReturnsEmptyListInitially() { List devices = client.getDevices(); - + assertNotNull(devices); assertTrue(devices.isEmpty()); } @@ -231,7 +231,7 @@ void testGetDevicesReturnsEmptyListInitially() { void testRequestDeviceList() throws ButtplugClientException, ExecutionException, InterruptedException { // Create test device - Device device = new Device(0,"Test Device",new HashMap<>(),100, "Display Name" ); + Device device = new Device(0, "Test Device", new HashMap<>(), 100, "Display Name"); HashMap devices = new HashMap<>(); devices.put(0, device); @@ -255,7 +255,7 @@ void testRequestDeviceList() throws ButtplugClientException, ExecutionException, assertEquals(1, client.getDevices().size()); addedDevice.set(null); - Device device2 = new Device(1,"Test Device 2",new HashMap<>(),100, "Other" ); + Device device2 = new Device(1, "Test Device 2", new HashMap<>(), 100, "Other"); devices.put(1, device2); client.onMessage(Collections.singletonList(deviceList)); @@ -288,7 +288,7 @@ void testRequestDeviceListWithError() { @Test void testSendDeviceMessageWithValidDevice() throws Exception { // Add a device first - Device device = new Device(5,"Test Device",new HashMap<>(),100, "Display Name" ); + Device device = new Device(5, "Test Device", new HashMap<>(), 100, "Display Name"); HashMap devices = new HashMap<>(); devices.put(5, device); @@ -311,7 +311,7 @@ void testSendDeviceMessageWithValidDevice() throws Exception { @Test void testSendDeviceMessageWithInvalidDevice() { - Device device = new Device(999,"Invalid Device",new HashMap<>(),100, "" ); + Device device = new Device(999, "Invalid Device", new HashMap<>(), 100, ""); ButtplugClientDevice clientDevice = new ButtplugClientDevice(client, device); @@ -328,7 +328,7 @@ void testSendDeviceMessageWithInvalidDevice() { @Test void testDisconnect() { client.setConnectionState(ButtplugClient.ConnectionState.CONNECTED); - + CompletableFuture future = new CompletableFuture<>(); client.scheduleWait(10, future); @@ -364,10 +364,10 @@ void testDoHandshakeWithPing() throws InterruptedException { client.doHandshake(); assertEquals(ButtplugClient.ConnectionState.CONNECTED, client.getConnectionState()); - + // Wait a bit to see if ping timer fires Thread.sleep(300); - + // Verify ping was sent boolean foundPing = false; for (ButtplugMessage msg : client.sentMessages) { @@ -391,8 +391,8 @@ void testDoHandshakeWithError() { @Test void testMultipleDevicesInDeviceList() throws Exception { - Device device1 = new Device(0,"Device 1",new HashMap<>(),100, "" ); - Device device2 = new Device(1,"Device 2",new HashMap<>(),100, "" ); + Device device1 = new Device(0, "Device 1", new HashMap<>(), 100, ""); + Device device2 = new Device(1, "Device 2", new HashMap<>(), 100, ""); HashMap devices = new HashMap<>(); devices.put(0, device1); @@ -437,7 +437,7 @@ void testWaitForOk() throws ExecutionException, InterruptedException { assertTrue(client.waitForOk(okFuture)); CompletableFuture errorFuture = CompletableFuture.completedFuture( - new Error("Error", Error.ErrorClass.ERROR_UNKNOWN, 1) + new Error("Error", Error.ErrorClass.ERROR_UNKNOWN, 1) ); assertFalse(client.waitForOk(errorFuture)); } @@ -447,10 +447,10 @@ void testWaitForOk() throws ExecutionException, InterruptedException { */ private static class TestButtplugClient extends ButtplugClient { private final List messageQueue = new ArrayList<>(); - private int queueIndex = 0; ButtplugMessage lastSentMessage; List sentMessages = new ArrayList<>(); boolean cleanupCalled = false; + private int queueIndex = 0; public TestButtplugClient(String clientName) { super(clientName); @@ -464,7 +464,7 @@ public void setNextResponse(ButtplugMessage message) { protected CompletableFuture sendMessage(ButtplugMessage msg) { lastSentMessage = msg; sentMessages.add(msg); - + CompletableFuture future = new CompletableFuture<>(); scheduleWait(msg.getId(), future); @@ -475,7 +475,7 @@ protected CompletableFuture sendMessage(ButtplugMessage msg) { } else { onMessage(Collections.singletonList(new Ok(msg.getId()))); } - + return future; } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceExceptionTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceExceptionTest.java index a56fb4a..9534073 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceExceptionTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceExceptionTest.java @@ -2,7 +2,9 @@ import io.github.blackspherefollower.buttplug4j.ButtplugException; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class ButtplugDeviceExceptionTest { @@ -10,7 +12,7 @@ public class ButtplugDeviceExceptionTest { public void testExceptionWithMessage() { String errorMessage = "Device not found"; ButtplugDeviceException exception = new ButtplugDeviceException(errorMessage); - + assertEquals(errorMessage, exception.getMessage()); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceFeatureExceptionTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceFeatureExceptionTest.java index a86283d..37ec1e2 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceFeatureExceptionTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugDeviceFeatureExceptionTest.java @@ -2,14 +2,16 @@ import io.github.blackspherefollower.buttplug4j.ButtplugException; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class ButtplugDeviceFeatureExceptionTest { @Test public void testExceptionWithMessage() { ButtplugDeviceFeatureException exception = new ButtplugDeviceFeatureException("slap"); - + assertEquals("Buttplug Device Feature does not support slap", exception.getMessage()); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugProtocolExceptionTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugProtocolExceptionTest.java index b358461..db87aee 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugProtocolExceptionTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugProtocolExceptionTest.java @@ -3,7 +3,9 @@ import com.fasterxml.jackson.core.JsonParseException; import io.github.blackspherefollower.buttplug4j.ButtplugException; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class ButtplugProtocolExceptionTest { @@ -12,7 +14,7 @@ public void testExceptionWithMessage() { String errorMessage = "Invalid protocol message"; JsonParseException cause = new JsonParseException(errorMessage); ButtplugProtocolException exception = new ButtplugProtocolException(cause); - + assertEquals("Buttplug JSON message exception", exception.getMessage()); assertEquals(errorMessage, exception.getCause().getMessage()); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/DeviceFeatureTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/DeviceFeatureTest.java index 6393074..afcf7f0 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/DeviceFeatureTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/DeviceFeatureTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class DeviceFeatureTest { @@ -15,7 +15,7 @@ public void testDeviceFeatureCreation() { @Test public void testDeviceFeatureWithProperties() { DeviceFeature feature = new DeviceFeature(); - + // Test that the feature can be created and has expected behavior // The exact implementation depends on the DeviceFeature class structure assertNotNull(feature); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/ButtplugMessageTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/ButtplugMessageTest.java index aaf0b58..19aff69 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/ButtplugMessageTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/ButtplugMessageTest.java @@ -4,7 +4,8 @@ import io.github.blackspherefollower.buttplug4j.protocol.messages.Ping; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; public class ButtplugMessageTest { @@ -31,7 +32,7 @@ public void testSystemMessageId() { public void testDifferentMessageTypes() { ButtplugMessage okMsg = new Ok(1); ButtplugMessage pingMsg = new Ping(2); - + assertNotEquals(okMsg.getClass(), pingMsg.getClass()); assertNotEquals(okMsg.getId(), pingMsg.getId()); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java index f42a29f..82383f6 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java @@ -82,7 +82,7 @@ public void test() throws IOException, ButtplugProtocolException { assertEquals(0, dev2Features.get(0).getFeatureIndex()); assertEquals("Stroker", dev2Features.get(0).getFeatureDescription()); assertEquals(2, dev2Features.get(0).getOutput().size()); - assertArrayEquals(new String[]{"Oscillate","PositionWithDuration"}, dev2Features.get(0).getOutput().stream().map(outputDescriptor -> outputDescriptor.getClass().getSimpleName()).toArray()); + assertArrayEquals(new String[]{"Oscillate", "PositionWithDuration"}, dev2Features.get(0).getOutput().stream().map(outputDescriptor -> outputDescriptor.getClass().getSimpleName()).toArray()); assertEquals(1, dev2Features.get(0).getInput().size()); assertEquals(1, dev2Features.get(1).getFeatureIndex()); assertArrayEquals(new String[]{"PositionInput"}, dev2Features.get(0).getInput().stream().map(inputDescriptor -> inputDescriptor.getClass().getSimpleName()).toArray()); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java index 5375670..d12028e 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java @@ -17,7 +17,8 @@ import java.util.List; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class InputCmdTest { diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java index 960c73c..b2a1627 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java @@ -35,7 +35,7 @@ public static void setup() throws IOException { @Test public void testInputReadingCreation() { InputReading reading = new InputReading(1, 0, 0); - + assertEquals(1, reading.getId()); assertEquals(0, reading.getDeviceIndex()); assertNotNull(reading); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java index 33a9fcc..eb47d3d 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java @@ -47,7 +47,7 @@ public void testVibrate() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Vibrate.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Vibrate)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Vibrate) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -72,7 +72,7 @@ public void testRotate() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Rotate.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Rotate)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Rotate) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -97,7 +97,7 @@ public void testRotateBackwards() throws IOException, ButtplugProtocolException assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Rotate.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(-5, ((OutputCmd.Rotate)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(-5, ((OutputCmd.Rotate) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -122,7 +122,7 @@ public void testPosition() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Position.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Position)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Position) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -147,7 +147,7 @@ public void testSpray() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Spray.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Spray)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Spray) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -172,7 +172,7 @@ public void testConstrict() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Constrict.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Constrict)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Constrict) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -197,7 +197,7 @@ public void testOscillate() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Oscillate.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Oscillate)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Oscillate) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -222,7 +222,7 @@ public void testTemperature() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Temperature.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Temperature)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Temperature) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -247,7 +247,7 @@ public void testLed() throws IOException, ButtplugProtocolException { assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.Led.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.Led)((OutputCmd) msgs.get(0)).getCommand()).getValue()); + assertEquals(5, ((OutputCmd.Led) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -272,8 +272,8 @@ public void testPositionWithDuration() throws IOException, ButtplugProtocolExcep assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.PositionWithDuration.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.PositionWithDuration)((OutputCmd) msgs.get(0)).getCommand()).getPosition()); - assertEquals(10, ((OutputCmd.PositionWithDuration)((OutputCmd) msgs.get(0)).getCommand()).getDuration()); + assertEquals(5, ((OutputCmd.PositionWithDuration) ((OutputCmd) msgs.get(0)).getCommand()).getPosition()); + assertEquals(10, ((OutputCmd.PositionWithDuration) ((OutputCmd) msgs.get(0)).getCommand()).getDuration()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/util/PairTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/util/PairTest.java index 9096083..023d73d 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/util/PairTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/util/PairTest.java @@ -1,6 +1,7 @@ package io.github.blackspherefollower.buttplug4j.util; import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; public class PairTest { @@ -8,7 +9,7 @@ public class PairTest { @Test public void testPairCreation() { Pair pair = new Pair<>("test", 42); - + assertEquals("test", pair.getLeft()); assertEquals(42, pair.getRight()); } @@ -16,7 +17,7 @@ public void testPairCreation() { @Test public void testPairWithNullValues() { Pair pair = new Pair<>(null, null); - + assertNull(pair.getLeft()); assertNull(pair.getRight()); } @@ -24,10 +25,10 @@ public void testPairWithNullValues() { @Test public void testPairSetters() { Pair pair = new Pair<>("initial", 1); - + pair.setLeft("updated"); pair.setRight(2); - + assertEquals("updated", pair.getLeft()); assertEquals(2, pair.getRight()); } @@ -37,7 +38,7 @@ public void testPairEquality() { Pair pair1 = new Pair<>("test", 42); Pair pair2 = new Pair<>("test", 42); Pair pair3 = new Pair<>("different", 42); - + assertEquals(pair1, pair2); assertNotEquals(pair1, pair3); } @@ -46,7 +47,7 @@ public void testPairEquality() { public void testPairHashCode() { Pair pair1 = new Pair<>("test", 42); Pair pair2 = new Pair<>("test", 42); - + assertEquals(pair1.hashCode(), pair2.hashCode()); } @@ -54,7 +55,7 @@ public void testPairHashCode() { public void testPairToString() { Pair pair = new Pair<>("test", 42); String str = pair.toString(); - + assertNotNull(str); assertTrue(str.contains("test")); assertTrue(str.contains("42")); @@ -63,7 +64,7 @@ public void testPairToString() { @Test public void testPairWithDifferentTypes() { Pair pair = new Pair<>(3.14, true); - + assertEquals(3.14, pair.getLeft()); assertEquals(true, pair.getRight()); } From ba8c39d1e0caae375e4ff7ce4097ac8a63f1a784 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Mon, 29 Dec 2025 19:18:11 +0000 Subject: [PATCH 5/9] chore: Fix the InputCmd stuff to match ic3b3 --- .../client/ButtplugWSClientMockTest.java | 4 ++-- .../ButtplugClientWSJettyClientTest.java | 4 ++-- .../client/ButtplugClientDeviceFeature.java | 7 +----- .../protocol/messages/DeviceFeature.java | 24 ++++++------------- .../protocol/messages/InputCmd.java | 4 ++-- .../protocol/messages/InputReading.java | 24 +++++++++++++++---- .../protocol/messages/OutputCmd.java | 21 ++++++---------- .../ButtplugClientDeviceFeatureTest.java | 4 ++-- .../protocol/messages/DeviceListTest.java | 2 +- .../protocol/messages/InputCmdTest.java | 6 ++--- .../protocol/messages/InputReadingTest.java | 17 +++++++------ .../protocol/messages/OutputCmdTest.java | 4 ++-- 12 files changed, 57 insertions(+), 64 deletions(-) diff --git a/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java b/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java index 3b4ba51..52f5004 100644 --- a/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java +++ b/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import java.net.URI; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; @@ -49,7 +50,6 @@ public void TestConnect() throws Exception { } @Test - @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void TestBattery() throws Exception { try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) { Thread.sleep(500); @@ -65,7 +65,7 @@ public void TestBattery() throws Exception { for (ButtplugClientDevice dev : client.getDevices()) { for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { if (feat.HasBattery()) { - ButtplugMessage res = feat.ReadBattery().get(); + ButtplugMessage res = feat.ReadBattery().get(2, TimeUnit.SECONDS); if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) { InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData(); int battery = reading.getValue(); diff --git a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java index 2b37ebf..4c141aa 100644 --- a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java +++ b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import java.net.URI; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; @@ -52,7 +53,6 @@ public void TestConnect() throws Exception { } @Test - @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void TestBattery() throws Exception { try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) { Thread.sleep(500); @@ -68,7 +68,7 @@ public void TestBattery() throws Exception { for (ButtplugClientDevice dev : client.getDevices()) { for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { if (feat.HasBattery()) { - ButtplugMessage res = feat.ReadBattery().get(); + ButtplugMessage res = feat.ReadBattery().get(2, TimeUnit.SECONDS); if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) { InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData(); int battery = reading.getValue(); diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java index 5072ef1..1038e97 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeature.java @@ -43,7 +43,7 @@ private int GetStepFromFloat(final String type, final float value) throws Buttpl steps *= value; return (int) Math.floor(steps); } else if (desc instanceof DeviceFeature.PositionWithDuration) { - double steps = ((DeviceFeature.PositionWithDuration) desc).getPosition()[1]; + double steps = ((DeviceFeature.PositionWithDuration) desc).getValue()[1]; steps *= value; return (int) Math.floor(steps); } else { @@ -61,11 +61,6 @@ private void CheckStepRange(final String type, final float value) throws Buttplu if (value > steps || value < 0) { throw new ButtplugDeviceFeatureException("Range error"); } - } else if (desc instanceof DeviceFeature.PositionWithDuration) { - int steps = ((DeviceFeature.PositionWithDuration) desc).getPosition()[1]; - if (value > steps || value < 0) { - throw new ButtplugDeviceFeatureException("Range error"); - } } else { throw new ButtplugDeviceFeatureException(type); } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java index 7ee4176..569ec40 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java @@ -189,30 +189,20 @@ public Position() { } } - public static class PositionWithDuration implements OutputDescriptor { - @JsonProperty(value = "Position", required = true) - private int[] position; + public static class PositionWithDuration extends SteppedOutputDescriptor { @JsonProperty(value = "Duration", required = true) private int[] duration; - public PositionWithDuration(int[] position, int[] duration) { - this.position = position; + public PositionWithDuration(int[] value, int[] duration) { + super(value); this.duration = duration; } public PositionWithDuration() { - this.position = new int[]{0, 0}; + super(new int[]{0, 0}); this.duration = new int[]{0, 0}; } - public int[] getPosition() { - return position; - } - - public void setPosition(int[] position) { - this.position = position; - } - public int[] getDuration() { return duration; } @@ -230,7 +220,7 @@ public boolean equals(Object o) { return false; } PositionWithDuration that = (PositionWithDuration) o; - return java.util.Arrays.equals(position, that.position) && java.util.Arrays.equals(duration, that.duration); + return java.util.Arrays.equals(getValue(), that.getValue()) && java.util.Arrays.equals(duration, that.duration); } } @@ -243,7 +233,7 @@ public boolean equals(Object o) { @JsonSubTypes.Type(value = DeviceFeature.PositionInput.class, name = "Position") }) public static class InputDescriptor { - @JsonProperty(value = "InputCommands", required = true) + @JsonProperty(value = "Command", required = true) private ArrayList input; public InputDescriptor(ArrayList input) { @@ -260,7 +250,7 @@ public void setInput(ArrayList input) { } public static class RangedInputDescriptor extends InputDescriptor { - @JsonProperty(value = "ValueRange", required = true) + @JsonProperty(value = "Value", required = true) private int[][] valueRange; public RangedInputDescriptor(ArrayList input, int[][] valueRange) { diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java index b6ffba8..573dd31 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmd.java @@ -8,10 +8,10 @@ public class InputCmd extends ButtplugDeviceMessage { @JsonProperty(value = "FeatureIndex", required = true) private int featureIndex; - @JsonProperty(value = "InputType", required = true) + @JsonProperty(value = "Type", required = true) private String inputType; - @JsonProperty(value = "InputCommand", required = true) + @JsonProperty(value = "Command", required = true) private InputCommandType inputCommand; public InputCmd(int id, final long deviceIndex, final int featureIndex, final String inputType, final InputCommandType inputCommand) { diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java index ad0846e..3905f36 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java @@ -1,19 +1,25 @@ package io.github.blackspherefollower.buttplug4j.protocol.messages; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.github.blackspherefollower.buttplug4j.protocol.ButtplugDeviceMessage; public class InputReading extends ButtplugDeviceMessage { @JsonProperty(value = "FeatureIndex", required = true) private int featureIndex; - @JsonProperty(value = "Data", required = true) + @JsonProperty(value = "Reading", required = true) private InputData data; public InputReading(int id, long deviceIndex, int featureIndex) { super(id, deviceIndex); this.featureIndex = featureIndex; } + public InputReading() { + super(-1, -1); + this.featureIndex = -1; + } public InputData getData() { return data; @@ -31,11 +37,19 @@ public void setFeatureIndex(int featureIndex) { this.featureIndex = featureIndex; } - public interface InputData { + @JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) + @JsonSubTypes({ + @JsonSubTypes.Type(value = BatteryData.class, name = "Battery"), + @JsonSubTypes.Type(value = RssiData.class, name = "RSSI"), + @JsonSubTypes.Type(value = ButtonData.class, name = "Button"), + @JsonSubTypes.Type(value = PresureData.class, name = "Pressure"), + @JsonSubTypes.Type(value = Position.class, name = "Position"), + }) + public static class InputData { } - static public class InputIntegerData { - @JsonProperty(value = "Data", required = true) + static public class InputIntegerData extends InputData { + @JsonProperty(value = "Value", required = true) int value; public int getValue() { @@ -58,4 +72,6 @@ static public class ButtonData extends InputIntegerData { static public class PresureData extends InputIntegerData { } + static public class Position extends InputIntegerData { + } } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmd.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmd.java index 10f1e00..239ebd3 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmd.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmd.java @@ -61,6 +61,9 @@ public abstract static class ValueCommand implements IOutputCommand { protected ValueCommand(int value) { this.value = value; } + protected ValueCommand() { + this.value = 0; + } public int getValue() { return value; @@ -151,30 +154,20 @@ public Position() { } } - public static class PositionWithDuration implements IOutputCommand { - @JsonProperty(value = "Position", required = true) - private int position; + public static class PositionWithDuration extends ValueCommand { @JsonProperty(value = "Duration", required = true) private int duration; - public PositionWithDuration(int position, int duration) { - this.position = position; + public PositionWithDuration(int value, int duration) { + super(value); this.duration = duration; } public PositionWithDuration() { - this.position = 0; + super(); this.duration = 0; } - public int getPosition() { - return position; - } - - public void setPosition(int position) { - this.position = position; - } - public int getDuration() { return duration; } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java index e2165a7..e438d02 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/client/ButtplugClientDeviceFeatureTest.java @@ -238,7 +238,7 @@ void testPositionWithDurationWithValidStep() throws Exception { ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); assertInstanceOf(OutputCmd.PositionWithDuration.class, captor.getValue()); - assertEquals(15, ((OutputCmd.PositionWithDuration) captor.getValue()).getPosition()); + assertEquals(15, ((OutputCmd.PositionWithDuration) captor.getValue()).getValue()); assertEquals(500, ((OutputCmd.PositionWithDuration) captor.getValue()).getDuration()); } @@ -257,7 +257,7 @@ void testPositionWithDurationFloatWithValidValue() throws Exception { ArgumentCaptor captor = ArgumentCaptor.forClass(OutputCmd.IOutputCommand.class); verify(mockDevice).sendOutputCommand(eq(0), captor.capture()); assertInstanceOf(OutputCmd.PositionWithDuration.class, captor.getValue()); - assertEquals(20, ((OutputCmd.PositionWithDuration) captor.getValue()).getPosition()); + assertEquals(20, ((OutputCmd.PositionWithDuration) captor.getValue()).getValue()); assertEquals(500, ((OutputCmd.PositionWithDuration) captor.getValue()).getDuration()); } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java index 82383f6..a2f65a9 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java @@ -33,7 +33,7 @@ public static void setup() throws IOException { @Test public void test() throws IOException, ButtplugProtocolException { - String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"InputCommands\":[\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Position\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"InputCommands\":[\"Subscribe\",\"Read\"],\"ValueRange\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"InputCommands\":[\"Read\"],\"ValueRange\":[[-10,0],[-100,0]]}}}}}}}}]"; + String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Value\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"Command\":[\"Subscribe\",\"Read\"],\"Value\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"Command\":[\"Read\"],\"Value\":[[-10,0],[-100,0]]}}}}}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java index d12028e..819a26e 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java @@ -34,7 +34,7 @@ public static void setup() throws IOException { @Test public void testInputCmdSubscribe() throws IOException, ButtplugProtocolException { - String testStr = "[{\"InputCmd\":{\"Id\":1,\"DeviceIndex\":0,\"FeatureIndex\":0,\"InputType\":\"Battery\",\"InputCommand\":\"Subscribe\"}}]"; + String testStr = "[{\"InputCmd\":{\"Id\":1,\"DeviceIndex\":0,\"FeatureIndex\":0,\"Type\":\"Battery\",\"Command\":\"Subscribe\"}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(Error::getError).collect(Collectors.joining("\n"))); @@ -59,7 +59,7 @@ public void testInputCmdSubscribe() throws IOException, ButtplugProtocolExceptio @Test public void testInputCmdUnsubscribe() throws IOException, ButtplugProtocolException { - String testStr = "[{\"InputCmd\":{\"Id\":2,\"DeviceIndex\":1,\"FeatureIndex\":1,\"InputType\":\"RSSI\",\"InputCommand\":\"Unsubscribe\"}}]"; + String testStr = "[{\"InputCmd\":{\"Id\":2,\"DeviceIndex\":1,\"FeatureIndex\":1,\"Type\":\"RSSI\",\"Command\":\"Unsubscribe\"}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(Error::getError).collect(Collectors.joining("\n"))); @@ -84,7 +84,7 @@ public void testInputCmdUnsubscribe() throws IOException, ButtplugProtocolExcept @Test public void testInputCmdRead() throws IOException, ButtplugProtocolException { - String testStr = "[{\"InputCmd\":{\"Id\":3,\"DeviceIndex\":0,\"FeatureIndex\":0,\"InputType\":\"Button\",\"InputCommand\":\"Read\"}}]"; + String testStr = "[{\"InputCmd\":{\"Id\":3,\"DeviceIndex\":0,\"FeatureIndex\":0,\"Type\":\"Button\",\"Command\":\"Read\"}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(Error::getError).collect(Collectors.joining("\n"))); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java index b2a1627..5b8ed98 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java @@ -63,23 +63,22 @@ public void testInputDataInterfaces() { } @Test - @Disabled("See https://github.com/buttplugio/buttplug/issues/801") public void testBatteryReading() throws ButtplugProtocolException { - String testStr = "[{\"InputReading\":{\"Id\":1,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Data\":{\"Battery\":{\"Data\":100}}}}]"; + String testStr = "[{\"InputReading\":{\"Id\":10,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Reading\":{\"Battery\":{\"Value\":100}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); - assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + //assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); List msgs = parser.parseJson(testStr); assertEquals(1, msgs.size()); - assertEquals(InputReading.BatteryData.class, msgs.get(0).getClass()); - assertEquals(1, msgs.get(0).getId(), 1); - assertEquals(4, ((ServerInfo) msgs.get(0)).getProtocolVersionMajor()); - assertEquals(0, ((ServerInfo) msgs.get(0)).getProtocolVersionMinor()); - assertEquals(500, ((ServerInfo) msgs.get(0)).getMaxPingTime()); - assertEquals("Websocket Server", ((ServerInfo) msgs.get(0)).getServerName()); + assertEquals(InputReading.class, msgs.get(0).getClass()); + assertEquals(10, msgs.get(0).getId()); + assertEquals(0, ((InputReading) msgs.get(0)).getDeviceIndex()); + assertEquals(1, ((InputReading) msgs.get(0)).getFeatureIndex()); + assertEquals(InputReading.BatteryData.class, ((InputReading) msgs.get(0)).getData().getClass()); + assertEquals(100, ((InputReading.BatteryData)((InputReading) msgs.get(0)).getData()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java index eb47d3d..2bf70fe 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/OutputCmdTest.java @@ -258,7 +258,7 @@ public void testLed() throws IOException, ButtplugProtocolException { @Test public void testPositionWithDuration() throws IOException, ButtplugProtocolException { - String testStr = "[{\"OutputCmd\":{\"Id\":1,\"DeviceIndex\":0,\"FeatureIndex\":0,\"Command\":{\"PositionWithDuration\":{\"Position\":5,\"Duration\":10}}}}]"; + String testStr = "[{\"OutputCmd\":{\"Id\":1,\"DeviceIndex\":0,\"FeatureIndex\":0,\"Command\":{\"PositionWithDuration\":{\"Value\":5,\"Duration\":10}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(Error::getError).collect(Collectors.joining("\n"))); @@ -272,7 +272,7 @@ public void testPositionWithDuration() throws IOException, ButtplugProtocolExcep assertEquals(0, ((OutputCmd) msgs.get(0)).getDeviceIndex()); assertEquals(0, ((OutputCmd) msgs.get(0)).getFeatureIndex()); assertInstanceOf(OutputCmd.PositionWithDuration.class, ((OutputCmd) msgs.get(0)).getCommand()); - assertEquals(5, ((OutputCmd.PositionWithDuration) ((OutputCmd) msgs.get(0)).getCommand()).getPosition()); + assertEquals(5, ((OutputCmd.PositionWithDuration) ((OutputCmd) msgs.get(0)).getCommand()).getValue()); assertEquals(10, ((OutputCmd.PositionWithDuration) ((OutputCmd) msgs.get(0)).getCommand()).getDuration()); String jsonOut = parser.formatJson(msgs); From fbc3ff16b219b44a69a5705b828855d4531b8745 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Tue, 30 Dec 2025 16:12:27 +0000 Subject: [PATCH 6/9] test: Re-enable disabled schema validation test --- .../buttplug4j/protocol/messages/InputReadingTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java index 5b8ed98..6386680 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java @@ -67,7 +67,7 @@ public void testBatteryReading() throws ButtplugProtocolException { String testStr = "[{\"InputReading\":{\"Id\":10,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Reading\":{\"Battery\":{\"Value\":100}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); - //assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); List msgs = parser.parseJson(testStr); From 0ecf6b3781f56bc8e3ea2219db64a23183ced581 Mon Sep 17 00:00:00 2001 From: blackspherefollower Date: Fri, 2 Jan 2026 14:54:32 +0000 Subject: [PATCH 7/9] feat: Update to match IC3 beta4 --- .../client/ButtplugWSClientMockTest.java | 4 +- .../ButtplugClientWSJettyClientTest.java | 4 +- .../utils/test/IntifaceEngineWrapper.java | 2 +- .../buttplug4j/utils/test/WSDMClient.java | 156 +++++++++--------- .../protocol/messages/DeviceFeature.java | 4 +- .../protocol/messages/InputReading.java | 17 +- .../protocol/messages/DeviceListTest.java | 65 +++++++- .../protocol/messages/ErrorTest.java | 29 +++- .../protocol/messages/InputCmdTest.java | 8 + .../protocol/messages/InputReadingTest.java | 124 ++++++++++++-- 10 files changed, 300 insertions(+), 113 deletions(-) diff --git a/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java b/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java index 52f5004..32782d6 100644 --- a/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java +++ b/buttplug4j.connectors.javax.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/javax/websocket/client/ButtplugWSClientMockTest.java @@ -66,8 +66,8 @@ public void TestBattery() throws Exception { for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { if (feat.HasBattery()) { ButtplugMessage res = feat.ReadBattery().get(2, TimeUnit.SECONDS); - if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) { - InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData(); + if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.Battery) { + InputReading.Battery reading = (InputReading.Battery) ((InputReading) res).getData(); int battery = reading.getValue(); System.out.println("Battery is " + battery); assertTrue(battery >= 0); diff --git a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java index 4c141aa..13b0841 100644 --- a/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java +++ b/buttplug4j.connectors.jetty.websocket.client/src/test/java/io/github/blackspherefollower/buttplug4j/connectors/jetty/websocket/client/ButtplugClientWSJettyClientTest.java @@ -69,8 +69,8 @@ public void TestBattery() throws Exception { for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) { if (feat.HasBattery()) { ButtplugMessage res = feat.ReadBattery().get(2, TimeUnit.SECONDS); - if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) { - InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData(); + if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.Battery) { + InputReading.Battery reading = (InputReading.Battery) ((InputReading) res).getData(); int battery = reading.getValue(); System.out.println("Battery is " + battery); assertTrue(battery >= 0); diff --git a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java index 11fa861..81c4644 100644 --- a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java +++ b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/IntifaceEngineWrapper.java @@ -56,7 +56,7 @@ public void setup(boolean listen, ArrayList extraArgs) throws Exception } } - ArrayList args = new ArrayList<>(Arrays.asList("intiface-engine", listen ? "--websocket-port" : "--websocket-client-address", listen ? String.valueOf(cport) : ("ws://127.0.0.1:" + String.valueOf(cport) + "/bob"), "--use-device-websocket-server", "--user-device-config-file", userConfig.toAbsolutePath().toString(), "--device-websocket-server-port", String.valueOf(dport), "--log", "TRACE")); + ArrayList args = new ArrayList<>(Arrays.asList("intiface-engine", listen ? "--websocket-port" : "--websocket-client-address", listen ? String.valueOf(cport) : ("ws://127.0.0.1:" + String.valueOf(cport) + "/bob"), "--use-device-websocket-server", "--user-device-config-file", userConfig.toAbsolutePath().toString(), "--device-websocket-server-port", String.valueOf(dport), "--log", "TRACE", "--allow-v4-spec")); args.addAll(extraArgs); ProcessBuilder pb = new ProcessBuilder(args); diff --git a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java index 3b5f7f5..8169d77 100644 --- a/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java +++ b/buttplug4j.utils.test/src/main/java/io/github/blackspherefollower/buttplug4j/utils/test/WSDMClient.java @@ -8,97 +8,45 @@ import java.net.http.HttpClient; import java.net.http.WebSocket; import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.*; public class WSDMClient { - private final WSDHeader header; - private final CompletableFuture connected = new CompletableFuture<>(); - public ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); - public int battery = 100; - private WebSocket client; + private WebSocket client; + private final WSDHeader header; + public ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); + private final CompletableFuture connected = new CompletableFuture<>(); - public WSDMClient(final URI url, final String identifier, final String address) throws Exception { - header = new WSDHeader(); - header.identifier = identifier; - header.address = address; + public int battery = 100; - HttpClient - .newHttpClient() - .newWebSocketBuilder() - .buildAsync(url, new WebSocketClient(this)) - .join(); - connected.get(10, TimeUnit.SECONDS); - - } - - public void onClose(int statusCode, String reason) { - this.client = null; - } - - public void onConnect(WebSocket client) { - this.client = client; - // Don't block the WS thread - new Thread(() -> { - try { - client.sendText(new ObjectMapper().writeValueAsString(header), true).get(1, TimeUnit.SECONDS); - } catch (JsonProcessingException | ExecutionException | InterruptedException | TimeoutException e) { - System.out.println("Failed to send header: " + e.getMessage()); - } - }).start(); - } - - public void onMessage(final String message) { - System.out.println("Got message: " + message); - if (message.startsWith("DeviceType;")) { - new Thread(() -> { - try { - sendMessage("Z:10:" + header.address + ";"); - if (!connected.isDone()) { - connected.complete(true); - } - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new RuntimeException(e); - } - - }).start(); - return; + static class WSDHeader { + @JsonProperty("identifier") + public String identifier; + @JsonProperty("address") + public String address; + @JsonProperty("version") + public int version = 0; } - if (message.startsWith("Battery;")) { - new Thread(() -> { - try { - sendMessage(battery + ";"); - connected.complete(true); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - throw new RuntimeException(e); - } - }).start(); - return; - } - messages.add(message); - } + public WSDMClient(final URI url, final String identifier, final String address) throws Exception { + header = new WSDHeader(); + header.identifier = identifier; + header.address = address; - protected void sendMessage(final String msg) throws ExecutionException, InterruptedException, TimeoutException { - client.sendBinary(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)), true).get(1, TimeUnit.SECONDS); - } + HttpClient + .newHttpClient() + .newWebSocketBuilder() + .buildAsync(url, new WebSocketClient(this)) + .join(); + connected.get(10, TimeUnit.SECONDS); - static class WSDHeader { - @JsonProperty("identifier") - public String identifier; - @JsonProperty("address") - public String address; - @JsonProperty("version") - public int version = 0; - } + } private static class WebSocketClient implements WebSocket.Listener { WSDMClient wsdmclient; - - public WebSocketClient(WSDMClient wsdmclient) { - this.wsdmclient = wsdmclient; - } + public WebSocketClient(WSDMClient wsdmclient) {this.wsdmclient = wsdmclient;} @Override public void onOpen(WebSocket webSocket) { @@ -135,4 +83,56 @@ public CompletionStage onBinary(WebSocket webSocket, ByteBuffer message, bool return WebSocket.Listener.super.onBinary(webSocket, message, last); } } -} + + + public void onClose(int statusCode, String reason) { + this.client = null; + } + + public void onConnect(WebSocket client) { + this.client = client; + // Don't block the WS thread + new Thread(() -> { + try { + client.sendText(new ObjectMapper().writeValueAsString(header), true).get(1, TimeUnit.SECONDS); + } catch (JsonProcessingException | ExecutionException | InterruptedException |TimeoutException e) { + System.out.println("Failed to send header: " + e.getMessage()); + } + }).start(); + } + + public void onMessage(final String message) { + System.out.println("Got message: " + message); + if(message.startsWith("DeviceType;")) { + new Thread(() -> { + try { + sendMessage("Z:10:" + header.address + ";"); + if(!connected.isDone()) { + connected.complete(true); + } + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } + + }).start(); + return; + } + if(message.startsWith("Battery;")) { + new Thread(() -> { + try { + sendMessage(battery + ";"); + connected.complete(true); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } + + }).start(); + return; + } + messages.add(message); + } + + protected void sendMessage(final String msg) throws ExecutionException, InterruptedException, TimeoutException { + client.sendBinary(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)), true).get(1, TimeUnit.SECONDS); + } + } diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java index 569ec40..7d0019a 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceFeature.java @@ -92,7 +92,7 @@ public int[] getValue() { return value; } - public void setStepCount(int[] value) { + public void setValue(int[] value) { this.value = value; } @@ -227,7 +227,7 @@ public boolean equals(Object o) { @JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) @JsonSubTypes({ @JsonSubTypes.Type(value = DeviceFeature.Battery.class, name = "Battery"), - @JsonSubTypes.Type(value = DeviceFeature.Rssi.class, name = "RSSI"), + @JsonSubTypes.Type(value = DeviceFeature.Rssi.class, name = "Rssi"), @JsonSubTypes.Type(value = DeviceFeature.Button.class, name = "Button"), @JsonSubTypes.Type(value = DeviceFeature.Pressure.class, name = "Pressure"), @JsonSubTypes.Type(value = DeviceFeature.PositionInput.class, name = "Position") diff --git a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java index 3905f36..a818323 100644 --- a/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java +++ b/buttplug4j/src/main/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReading.java @@ -39,10 +39,10 @@ public void setFeatureIndex(int featureIndex) { @JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) @JsonSubTypes({ - @JsonSubTypes.Type(value = BatteryData.class, name = "Battery"), - @JsonSubTypes.Type(value = RssiData.class, name = "RSSI"), - @JsonSubTypes.Type(value = ButtonData.class, name = "Button"), - @JsonSubTypes.Type(value = PresureData.class, name = "Pressure"), + @JsonSubTypes.Type(value = Battery.class, name = "Battery"), + @JsonSubTypes.Type(value = Rssi.class, name = "Rssi"), + @JsonSubTypes.Type(value = Button.class, name = "Button"), + @JsonSubTypes.Type(value = Presure.class, name = "Pressure"), @JsonSubTypes.Type(value = Position.class, name = "Position"), }) public static class InputData { @@ -61,17 +61,18 @@ public void setValue(int value) { } } - static public class BatteryData extends InputIntegerData { + static public class Battery extends InputIntegerData { } - static public class RssiData extends InputIntegerData { + static public class Rssi extends InputIntegerData { } - static public class ButtonData extends InputIntegerData { + static public class Button extends InputIntegerData { } - static public class PresureData extends InputIntegerData { + static public class Presure extends InputIntegerData { } + static public class Position extends InputIntegerData { } } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java index a2f65a9..07b3de6 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/DeviceListTest.java @@ -33,7 +33,7 @@ public static void setup() throws IOException { @Test public void test() throws IOException, ButtplugProtocolException { - String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Value\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"Command\":[\"Subscribe\",\"Read\"],\"Value\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"RSSI\":{\"Command\":[\"Read\"],\"Value\":[[-10,0],[-100,0]]}}}}}}}}]"; + String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Vibrator\",\"DeviceMessageTimingGap\":100,\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Clitoral Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Insertable Stimulator\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}},\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Battery\",\"Input\":{\"Battery\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,100]]}}}}},\"2\":{\"DeviceIndex\":2,\"DeviceName\":\"Test Stroker\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"User set name\",\"DeviceFeatures\":{\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Stroker\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]},\"PositionWithDuration\":{\"Value\":[0,100],\"Duration\":[0,2000]}},\"Input\":{\"Position\":{\"Command\":[\"Subscribe\",\"Read\"],\"Value\":[[0,0],[0,100]]}}},\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Bluetooth Radio RSSI\",\"Input\":{\"Rssi\":{\"Command\":[\"Read\"],\"Value\":[[-10,0],[-100,0]]}}}}}}}}]"; Validator.Result result = new ValidatorFactory().validate(schema, testStr); assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); @@ -99,4 +99,67 @@ public void test() throws IOException, ButtplugProtocolException { assertEquals(testStr, jsonOut); } + @Test + public void testObsure() throws IOException, ButtplugProtocolException { + String testStr = "[{\"DeviceList\":{\"Id\":5,\"Devices\":{\"0\":{\"DeviceIndex\":0,\"DeviceName\":\"Test Everything\",\"DeviceMessageTimingGap\":100,\"DeviceDisplayName\":\"Everything\",\"DeviceFeatures\":{" + + "\"0\":{\"FeatureIndex\":0,\"FeatureDescription\":\"Example Vibrate\",\"Output\":{\"Vibrate\":{\"Value\":[0,20]}}}," + + "\"1\":{\"FeatureIndex\":1,\"FeatureDescription\":\"Example Rotate\",\"Output\":{\"Rotate\":{\"Value\":[-20,20]}}}," + + "\"2\":{\"FeatureIndex\":2,\"FeatureDescription\":\"Example Oscillate\",\"Output\":{\"Oscillate\":{\"Value\":[0,20]}}}," + + "\"3\":{\"FeatureIndex\":3,\"FeatureDescription\":\"Example Constrict\",\"Output\":{\"Constrict\":{\"Value\":[0,20]}}}," + + "\"4\":{\"FeatureIndex\":4,\"FeatureDescription\":\"Example Temperature\",\"Output\":{\"Temperature\":{\"Value\":[0,20]}}}," + + "\"5\":{\"FeatureIndex\":5,\"FeatureDescription\":\"Example Spray\",\"Output\":{\"Spray\":{\"Value\":[0,1]}}}," + + "\"6\":{\"FeatureIndex\":6,\"FeatureDescription\":\"Example Led\",\"Output\":{\"Led\":{\"Value\":[0,255]}}}," + + "\"7\":{\"FeatureIndex\":7,\"FeatureDescription\":\"Example Position\",\"Output\":{\"Position\":{\"Value\":[0,255]}}}," + + "\"8\":{\"FeatureIndex\":8,\"FeatureDescription\":\"Example PositionWithDuration\",\"Output\":{\"PositionWithDuration\":{\"Value\":[0,255],\"Duration\":[0,2000]}}}," + + "\"9\":{\"FeatureIndex\":9,\"FeatureDescription\":\"Example Button\",\"Input\":{\"Button\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,1]]}}}," + + "\"10\":{\"FeatureIndex\":10,\"FeatureDescription\":\"Example Pressure\",\"Input\":{\"Pressure\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,100]]}}}," + + "\"11\":{\"FeatureIndex\":11,\"FeatureDescription\":\"Example Rssi\",\"Input\":{\"Rssi\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,100]]}}}," + + "\"12\":{\"FeatureIndex\":12,\"FeatureDescription\":\"Example Battery\",\"Input\":{\"Battery\":{\"Command\":[\"Read\"],\"Value\":[[0,0],[0,100]]}}}" + + "}}}}}]"; + + Validator.Result result = new ValidatorFactory().validate(schema, testStr); + assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + + ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); + List msgs = parser.parseJson(testStr); + + assertEquals(1, msgs.size()); + assertEquals(DeviceList.class, msgs.get(0).getClass()); + assertEquals(5, msgs.get(0).getId()); + assertEquals(1, ((DeviceList) msgs.get(0)).getDevices().size()); + + HashMap devs = ((DeviceList) msgs.get(0)).getDevices(); + assertNotNull(devs.get(0)); + assertEquals(0, devs.get(0).getDeviceIndex()); + assertEquals("Test Everything", devs.get(0).getDeviceName()); + assertEquals("Everything", devs.get(0).getDeviceDisplayName()); + assertEquals(100, devs.get(0).getDeviceMessageTimingGap()); + HashMap dev0Features = devs.get(0).getDeviceFeatures(); + assertEquals(13, dev0Features.size()); + + String[] outputNames = new String[]{"Vibrate", "Rotate", "Oscillate", "Constrict", "Temperature", "Spray", "Led", "Position", "PositionWithDuration"}; + for (int i = 0; i < outputNames.length; i++) { + assertEquals(i, dev0Features.get(i).getFeatureIndex()); + assertEquals("Example "+outputNames[i], dev0Features.get(i).getFeatureDescription()); + assertEquals(1, dev0Features.get(i).getOutput().size()); + assertArrayEquals(new String[]{outputNames[i]}, dev0Features.get(i).getOutput().stream().map(outputDescriptor -> outputDescriptor.getClass().getSimpleName()).toArray()); + assertNull(dev0Features.get(0).getInput()); + } + + String[] inputNames = new String[]{"Button", "Pressure", "Rssi", "Battery"}; + for (int i = 0; i < inputNames.length; i++) { + assertEquals(i+outputNames.length, dev0Features.get(i+outputNames.length).getFeatureIndex()); + assertEquals("Example "+inputNames[i], dev0Features.get(i+outputNames.length).getFeatureDescription()); + assertNull(dev0Features.get(i+outputNames.length).getOutput()); + assertEquals(1, dev0Features.get(i+outputNames.length).getInput().size()); + assertArrayEquals(new String[]{inputNames[i]}, dev0Features.get(i+outputNames.length).getInput().stream().map(inputDescriptor -> inputDescriptor.getClass().getSimpleName()).toArray()); + } + + String jsonOut = parser.formatJson(msgs); + assertEquals(testStr, jsonOut); + + jsonOut = parser.formatJson(msgs.get(0)); + assertEquals(testStr, jsonOut); + } + } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ErrorTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ErrorTest.java index 3c4d501..be2e79b 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ErrorTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/ErrorTest.java @@ -41,16 +41,16 @@ public void test() throws IOException, ButtplugProtocolException { ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); List msgs = parser.parseJson(testStr); - assertEquals(msgs.size(), 1); - assertEquals(msgs.get(0).getClass(), - Error.class); - assertEquals(msgs.get(0).getId(), 7); + assertEquals(1, msgs.size()); + assertEquals(Error.class, + msgs.get(0).getClass()); + assertEquals(7, msgs.get(0).getId()); assertEquals( - ((Error) msgs.get(0)).getErrorMessage(), - "TestError"); + "TestError", + ((Error) msgs.get(0)).getErrorMessage()); assertEquals( - ((Error) msgs.get(0)).getErrorCode(), - Error.ErrorClass.ERROR_DEVICE); + Error.ErrorClass.ERROR_DEVICE, + ((Error) msgs.get(0)).getErrorCode()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); @@ -59,4 +59,17 @@ public void test() throws IOException, ButtplugProtocolException { assertEquals(testStr, jsonOut); } + @Test + public void testException() throws IOException, ButtplugProtocolException { + Error e = new Error(new Exception("TestError"), 7); + + assertEquals(7, e.getId()); + assertEquals( + "TestError", + e.getException().getMessage()); + assertEquals( + Error.ErrorClass.ERROR_UNKNOWN, + e.getErrorCode()); + } + } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java index 819a26e..0068324 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputCmdTest.java @@ -102,4 +102,12 @@ public void testInputCmdRead() throws IOException, ButtplugProtocolException { jsonOut = parser.formatJson(msgs.get(0)); assertEquals(testStr, jsonOut); } + + @Test + public void testInputCmdReadInternal() throws IOException, ButtplugProtocolException { + InputCmd cmd = new InputCmd(1, 0, 0, "Battery", InputCommandType.READ); + + assertEquals(InputCommandType.READ, cmd.getInputCommand()); + assertEquals("Battery", cmd.getInputType()); + } } diff --git a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java index 6386680..a5678dd 100644 --- a/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java +++ b/buttplug4j/src/test/java/io/github/blackspherefollower/buttplug4j/protocol/messages/InputReadingTest.java @@ -51,15 +51,17 @@ public void testInputReadingInheritance() { @Test public void testInputDataInterfaces() { // Test that InputData interface classes exist - InputReading.BatteryData batteryData = new InputReading.BatteryData(); - InputReading.RssiData rssiData = new InputReading.RssiData(); - InputReading.ButtonData buttonData = new InputReading.ButtonData(); - InputReading.PresureData presureData = new InputReading.PresureData(); - - assertInstanceOf(InputReading.BatteryData.class, batteryData); - assertInstanceOf(InputReading.RssiData.class, rssiData); - assertInstanceOf(InputReading.ButtonData.class, buttonData); - assertInstanceOf(InputReading.PresureData.class, presureData); + InputReading.Battery batteryData = new InputReading.Battery(); + InputReading.Rssi rssiData = new InputReading.Rssi(); + InputReading.Button buttonData = new InputReading.Button(); + InputReading.Presure presureData = new InputReading.Presure(); + InputReading.Position positionData = new InputReading.Position(); + + assertInstanceOf(InputReading.Battery.class, batteryData); + assertInstanceOf(InputReading.Rssi.class, rssiData); + assertInstanceOf(InputReading.Button.class, buttonData); + assertInstanceOf(InputReading.Presure.class, presureData); + assertInstanceOf(InputReading.Position.class, positionData); } @Test @@ -77,8 +79,108 @@ public void testBatteryReading() throws ButtplugProtocolException { assertEquals(10, msgs.get(0).getId()); assertEquals(0, ((InputReading) msgs.get(0)).getDeviceIndex()); assertEquals(1, ((InputReading) msgs.get(0)).getFeatureIndex()); - assertEquals(InputReading.BatteryData.class, ((InputReading) msgs.get(0)).getData().getClass()); - assertEquals(100, ((InputReading.BatteryData)((InputReading) msgs.get(0)).getData()).getValue()); + assertEquals(InputReading.Battery.class, ((InputReading) msgs.get(0)).getData().getClass()); + assertEquals(100, ((InputReading.Battery)((InputReading) msgs.get(0)).getData()).getValue()); + + String jsonOut = parser.formatJson(msgs); + assertEquals(testStr, jsonOut); + + jsonOut = parser.formatJson(msgs.get(0)); + assertEquals(testStr, jsonOut); + } + + @Test + public void testRSSIReading() throws ButtplugProtocolException { + String testStr = "[{\"InputReading\":{\"Id\":10,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Reading\":{\"Rssi\":{\"Value\":-10}}}}]"; + + Validator.Result result = new ValidatorFactory().validate(schema, testStr); + assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + + ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); + List msgs = parser.parseJson(testStr); + + assertEquals(1, msgs.size()); + assertEquals(InputReading.class, msgs.get(0).getClass()); + assertEquals(10, msgs.get(0).getId()); + assertEquals(0, ((InputReading) msgs.get(0)).getDeviceIndex()); + assertEquals(1, ((InputReading) msgs.get(0)).getFeatureIndex()); + assertEquals(InputReading.Rssi.class, ((InputReading) msgs.get(0)).getData().getClass()); + assertEquals(-10, ((InputReading.Rssi)((InputReading) msgs.get(0)).getData()).getValue()); + + String jsonOut = parser.formatJson(msgs); + assertEquals(testStr, jsonOut); + + jsonOut = parser.formatJson(msgs.get(0)); + assertEquals(testStr, jsonOut); + } + + @Test + public void testPressureReading() throws ButtplugProtocolException { + String testStr = "[{\"InputReading\":{\"Id\":10,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Reading\":{\"Pressure\":{\"Value\":50}}}}]"; + + Validator.Result result = new ValidatorFactory().validate(schema, testStr); + assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + + ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); + List msgs = parser.parseJson(testStr); + + assertEquals(1, msgs.size()); + assertEquals(InputReading.class, msgs.get(0).getClass()); + assertEquals(10, msgs.get(0).getId()); + assertEquals(0, ((InputReading) msgs.get(0)).getDeviceIndex()); + assertEquals(1, ((InputReading) msgs.get(0)).getFeatureIndex()); + assertEquals(InputReading.Presure.class, ((InputReading) msgs.get(0)).getData().getClass()); + assertEquals(50, ((InputReading.Presure)((InputReading) msgs.get(0)).getData()).getValue()); + + String jsonOut = parser.formatJson(msgs); + assertEquals(testStr, jsonOut); + + jsonOut = parser.formatJson(msgs.get(0)); + assertEquals(testStr, jsonOut); + } + + @Test + public void testButtonReading() throws ButtplugProtocolException { + String testStr = "[{\"InputReading\":{\"Id\":10,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Reading\":{\"Button\":{\"Value\":1}}}}]"; + + Validator.Result result = new ValidatorFactory().validate(schema, testStr); + assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + + ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); + List msgs = parser.parseJson(testStr); + + assertEquals(1, msgs.size()); + assertEquals(InputReading.class, msgs.get(0).getClass()); + assertEquals(10, msgs.get(0).getId()); + assertEquals(0, ((InputReading) msgs.get(0)).getDeviceIndex()); + assertEquals(1, ((InputReading) msgs.get(0)).getFeatureIndex()); + assertEquals(InputReading.Button.class, ((InputReading) msgs.get(0)).getData().getClass()); + assertEquals(1, ((InputReading.Button)((InputReading) msgs.get(0)).getData()).getValue()); + + String jsonOut = parser.formatJson(msgs); + assertEquals(testStr, jsonOut); + + jsonOut = parser.formatJson(msgs.get(0)); + assertEquals(testStr, jsonOut); + } + + @Test + public void testPositionReading() throws ButtplugProtocolException { + String testStr = "[{\"InputReading\":{\"Id\":10,\"DeviceIndex\":0,\"FeatureIndex\":1,\"Reading\":{\"Position\":{\"Value\":25}}}}]"; + + Validator.Result result = new ValidatorFactory().validate(schema, testStr); + assertTrue(result.isValid(), result.getErrors().stream().map(error -> error.getError() + " - " + error.getInstanceLocation()).collect(Collectors.joining("\n"))); + + ButtplugJsonMessageParser parser = new ButtplugJsonMessageParser(); + List msgs = parser.parseJson(testStr); + + assertEquals(1, msgs.size()); + assertEquals(InputReading.class, msgs.get(0).getClass()); + assertEquals(10, msgs.get(0).getId()); + assertEquals(0, ((InputReading) msgs.get(0)).getDeviceIndex()); + assertEquals(1, ((InputReading) msgs.get(0)).getFeatureIndex()); + assertEquals(InputReading.Position.class, ((InputReading) msgs.get(0)).getData().getClass()); + assertEquals(25, ((InputReading.Position)((InputReading) msgs.get(0)).getData()).getValue()); String jsonOut = parser.formatJson(msgs); assertEquals(testStr, jsonOut); From 526d24d7b39c6833a5b25e7e207335292af6a6f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 4 Jan 2026 13:37:42 +0000 Subject: [PATCH 8/9] build(deps): bump org.jmdns:jmdns from 3.6.1 to 3.6.2 Bumps [org.jmdns:jmdns](https://github.com/jmdns/jmdns) from 3.6.1 to 3.6.2. - [Release notes](https://github.com/jmdns/jmdns/releases) - [Changelog](https://github.com/jmdns/jmdns/blob/main/CHANGELOG.txt) - [Commits](https://github.com/jmdns/jmdns/compare/3.6.1...3.6.2) --- updated-dependencies: - dependency-name: org.jmdns:jmdns dependency-version: 3.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- buttplug4j.utils.mdns/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buttplug4j.utils.mdns/build.gradle b/buttplug4j.utils.mdns/build.gradle index ae08bf6..f92fcac 100644 --- a/buttplug4j.utils.mdns/build.gradle +++ b/buttplug4j.utils.mdns/build.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - api 'org.jmdns:jmdns:3.6.1' + api 'org.jmdns:jmdns:3.6.3' api 'org.slf4j:slf4j-simple:2.0.17' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation project(':buttplug4j.utils.test') From 74e02b48a47d4c46976a0eeb927e40b91174c52a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 14:05:03 +0000 Subject: [PATCH 9/9] build(deps): bump org.junit.platform:junit-platform-launcher Bumps [org.junit.platform:junit-platform-launcher](https://github.com/junit-team/junit-framework) from 1.13.4 to 6.0.1. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/commits/r6.0.1) --- updated-dependencies: - dependency-name: org.junit.platform:junit-platform-launcher dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- buttplug4j.connectors.javax.websocket.client/build.gradle | 2 +- buttplug4j.connectors.javax.websocket.server/build.gradle | 2 +- buttplug4j.connectors.jetty.websocket.client/build.gradle | 2 +- buttplug4j.utils.mdns/build.gradle | 2 +- buttplug4j/build.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/buttplug4j.connectors.javax.websocket.client/build.gradle b/buttplug4j.connectors.javax.websocket.client/build.gradle index cc3ff7d..24a8840 100644 --- a/buttplug4j.connectors.javax.websocket.client/build.gradle +++ b/buttplug4j.connectors.javax.websocket.client/build.gradle @@ -15,7 +15,7 @@ dependencies { api 'org.eclipse.jetty.websocket:websocket-javax-client:10.0.26' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation project(':buttplug4j.utils.test') - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:6.0.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' } diff --git a/buttplug4j.connectors.javax.websocket.server/build.gradle b/buttplug4j.connectors.javax.websocket.server/build.gradle index 5a07e6b..cd573b2 100644 --- a/buttplug4j.connectors.javax.websocket.server/build.gradle +++ b/buttplug4j.connectors.javax.websocket.server/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'org.eclipse.jetty.websocket:websocket-javax-server:10.0.26' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation project(':buttplug4j.utils.test') - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:6.0.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' } diff --git a/buttplug4j.connectors.jetty.websocket.client/build.gradle b/buttplug4j.connectors.jetty.websocket.client/build.gradle index 61af4e9..3c48204 100644 --- a/buttplug4j.connectors.jetty.websocket.client/build.gradle +++ b/buttplug4j.connectors.jetty.websocket.client/build.gradle @@ -16,7 +16,7 @@ dependencies { api 'org.eclipse.jetty.websocket:websocket-api:9.4.58.v20250814' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation project(':buttplug4j.utils.test') - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:6.0.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' } diff --git a/buttplug4j.utils.mdns/build.gradle b/buttplug4j.utils.mdns/build.gradle index f92fcac..835b3de 100644 --- a/buttplug4j.utils.mdns/build.gradle +++ b/buttplug4j.utils.mdns/build.gradle @@ -15,7 +15,7 @@ dependencies { api 'org.slf4j:slf4j-simple:2.0.17' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation project(':buttplug4j.utils.test') - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:6.0.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' } diff --git a/buttplug4j/build.gradle b/buttplug4j/build.gradle index ba9ea31..0199f69 100644 --- a/buttplug4j/build.gradle +++ b/buttplug4j/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'dev.harrel:json-schema:1.8.2' testImplementation 'org.mockito:mockito-core:5.20.0' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:6.0.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4' }