Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7
8mod util;
9use std::time::Duration;
10
11use buttplug_server_device_config::Endpoint;
12pub use util::test_device_manager::check_test_recv_value;
13
14use buttplug_core::message::{
15 StartScanningV0,
16 serializer::{ButtplugMessageSerializer, ButtplugSerializedMessage},
17};
18use buttplug_server::{
19 ButtplugServerBuilder,
20 device::hardware::{HardwareCommand, HardwareWriteCmd},
21 message::{ButtplugClientMessageVariant, serializer::ButtplugServerJSONSerializer},
22};
23use futures::{StreamExt, pin_mut};
24use util::test_server_with_device;
25use uuid::Uuid;
26
27#[tokio::test]
28async fn test_version0_connection() {
29 let server = ButtplugServerBuilder::default().finish().unwrap();
30 let serializer = ButtplugServerJSONSerializer::default();
31 let rsi = r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client"}}]"#;
32 let output = serializer
33 .deserialize(&rsi.to_owned().into())
34 .expect("Test, assuming infallible.");
35 let incoming = server
36 .parse_message(output[0].clone())
37 .await
38 .expect("Test, assuming infallible.");
39 let incoming_json = serializer.serialize(&vec![incoming]);
40 assert_eq!(
41 incoming_json,
42 r#"[{"ServerInfo":{"Id":1,"MajorVersion":0,"MinorVersion":0,"BuildVersion":0,"MessageVersion":0,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
43 );
44}
45
46#[tokio::test]
47async fn test_version2_connection() {
48 let server = ButtplugServerBuilder::default().finish().unwrap();
49 let serializer = ButtplugServerJSONSerializer::default();
50 let rsi =
51 r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client", "MessageVersion": 2}}]"#;
52 let output = serializer
53 .deserialize(&rsi.to_owned().into())
54 .expect("Test, assuming infallible.");
55 let incoming = server
56 .parse_message(output[0].clone())
57 .await
58 .expect("Test, assuming infallible.");
59 let incoming_json = serializer.serialize(&vec![incoming]);
60 assert_eq!(
61 incoming_json,
62 r#"[{"ServerInfo":{"Id":1,"MessageVersion":2,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
63 );
64}
65
66#[tokio::test]
67async fn test_version0_device_added_device_list() {
68 let (server, _) = test_server_with_device("Massage Demo");
69 let recv = server.event_stream();
70 pin_mut!(recv);
71 let serializer = ButtplugServerJSONSerializer::default();
72 let rsi = r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client"}}]"#;
73 let mut output = server
74 .parse_message(
75 serializer
76 .deserialize(&rsi.to_owned().into())
77 .expect("Test, assuming infallible.")[0]
78 .clone(),
79 )
80 .await
81 .expect("Test, assuming infallible.");
82 assert_eq!(
83 serializer.serialize(&vec!(output)),
84 r#"[{"ServerInfo":{"Id":1,"MajorVersion":0,"MinorVersion":0,"BuildVersion":0,"MessageVersion":0,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
85 );
86 // Skip JSON parsing here, we aren't converting versions.
87 let reply = server
88 .parse_message(ButtplugClientMessageVariant::V0(
89 StartScanningV0::default().into(),
90 ))
91 .await;
92 assert!(reply.is_ok(), "Should get back ok: {:?}", reply);
93 // Check that we got an event back about scanning finishing.
94 let mut msg = recv.next().await.expect("Test, assuming infallible.");
95 // We should receive ScanningFinished and DeviceAdded, but the order may change.
96 let possible_messages: Vec<ButtplugSerializedMessage> = vec![r#"[{"ScanningFinished":{"Id":0}}]"#.to_owned().into(), r#"[{"DeviceAdded":{"Id":0,"DeviceIndex":0,"DeviceName":"Aneros Vivi","DeviceMessages":["SingleMotorVibrateCmd","StopDeviceCmd"]}}]"#.to_owned().into()];
97 assert!(possible_messages.contains(&serializer.serialize(&vec!(msg))));
98 msg = recv.next().await.expect("Test, assuming infallible.");
99 // We should get back an aneros with only SingleMotorVibrateCmd
100 assert!(possible_messages.contains(&serializer.serialize(&vec!(msg))));
101 let rdl = serializer
102 .deserialize(&ButtplugSerializedMessage::Text(
103 r#"[{"RequestDeviceList": { "Id": 1}}]"#.to_owned(),
104 ))
105 .expect("Test, assuming infallible.");
106 output = server
107 .parse_message(rdl[0].clone())
108 .await
109 .expect("Test, assuming infallible.");
110 assert_eq!(
111 serializer.serialize(&vec!(output)),
112 r#"[{"DeviceList":{"Id":1,"Devices":[{"DeviceIndex":0,"DeviceName":"Aneros Vivi","DeviceMessages":["SingleMotorVibrateCmd","StopDeviceCmd"]}]}}]"#.to_owned().into()
113 );
114}
115
116#[tokio::test]
117async fn test_version0_singlemotorvibratecmd() {
118 tracing_subscriber::fmt::init();
119 let (server, mut device) = test_server_with_device("Massage Demo");
120 let recv = server.event_stream();
121 pin_mut!(recv);
122 let serializer = ButtplugServerJSONSerializer::default();
123 let rsi = r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client"}}]"#;
124 let output = server
125 .parse_message(
126 serializer
127 .deserialize(&rsi.to_owned().into())
128 .expect("Test, assuming infallible.")[0]
129 .clone(),
130 )
131 .await
132 .expect("Test, assuming infallible.");
133 assert_eq!(
134 serializer.serialize(&vec!(output)),
135 r#"[{"ServerInfo":{"Id":1,"MajorVersion":0,"MinorVersion":0,"BuildVersion":0,"MessageVersion":0,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
136 );
137 // Skip JSON parsing here, we aren't converting versions.
138 let reply = server
139 .parse_message(ButtplugClientMessageVariant::V0(
140 StartScanningV0::default().into(),
141 ))
142 .await;
143 assert!(reply.is_ok(), "Should get back ok: {:?}", reply);
144 // Check that we got an event back about scanning finishing.
145 let mut msg = recv.next().await.expect("Test, assuming infallible.");
146 // We should receive ScanningFinished and DeviceAdded, but the order may change.
147 let possible_messages: Vec<ButtplugSerializedMessage> = vec![r#"[{"ScanningFinished":{"Id":0}}]"#.to_owned().into(), r#"[{"DeviceAdded":{"Id":0,"DeviceIndex":0,"DeviceName":"Aneros Vivi","DeviceMessages":["SingleMotorVibrateCmd","StopDeviceCmd"]}}]"#.to_owned().into()];
148 assert!(possible_messages.contains(&serializer.serialize(&vec!(msg))));
149 msg = recv.next().await.expect("Test, assuming infallible.");
150 // We should get back an aneros with only SingleMotorVibrateCmd
151 assert!(possible_messages.contains(&serializer.serialize(&vec!(msg))));
152 let output2 = server
153 .parse_message(
154 serializer
155 .deserialize(
156 &r#"[{"SingleMotorVibrateCmd": { "Id": 2, "DeviceIndex": 0, "Speed": 0.5}}]"#
157 .to_owned()
158 .into(),
159 )
160 .expect("Test, assuming infallible.")[0]
161 .clone(),
162 )
163 .await
164 .expect("Test, assuming infallible.");
165 assert_eq!(
166 serializer.serialize(&vec!(output2)),
167 r#"[{"Ok":{"Id":2}}]"#.to_owned().into()
168 );
169 check_test_recv_value(
170 &Duration::from_millis(150),
171 &mut device,
172 HardwareCommand::Write(HardwareWriteCmd::new(
173 &[Uuid::nil()],
174 Endpoint::Tx,
175 vec![0xF1, 64],
176 false,
177 )),
178 )
179 .await;
180}
181
182#[tokio::test]
183async fn test_version1_singlemotorvibratecmd() {
184 let (server, mut device) = test_server_with_device("Massage Demo");
185 let recv = server.event_stream();
186 pin_mut!(recv);
187 let serializer = ButtplugServerJSONSerializer::default();
188 let rsi =
189 r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client", "MessageVersion": 1}}]"#;
190 let output = server
191 .parse_message(
192 serializer
193 .deserialize(&rsi.to_owned().into())
194 .expect("Test, assuming infallible.")[0]
195 .clone(),
196 )
197 .await
198 .expect("Test, assuming infallible.");
199 assert_eq!(
200 serializer.serialize(&vec!(output)),
201 r#"[{"ServerInfo":{"Id":1,"MajorVersion":0,"MinorVersion":0,"BuildVersion":0,"MessageVersion":1,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
202 );
203 // Skip JSON parsing here, we aren't converting versions.
204 let reply = server
205 .parse_message(ButtplugClientMessageVariant::V1(
206 StartScanningV0::default().into(),
207 ))
208 .await;
209 assert!(reply.is_ok(), "Should get back ok: {:?}", reply);
210 // Check that we got an event back about scanning finishing.
211 let mut msg = recv.next().await.expect("Test, assuming infallible.");
212 let mut smsg = serializer.serialize(&vec![msg]);
213 // We should receive ScanningFinished and DeviceAdded, but the order may change.
214 let possible_messages: Vec<ButtplugSerializedMessage> = vec![r#"[{"ScanningFinished":{"Id":0}}]"#.to_owned().into(), r#"[{"DeviceAdded":{"Id":0,"DeviceIndex":0,"DeviceName":"Aneros Vivi","DeviceMessages":{"VibrateCmd":{"FeatureCount":2},"stop_device_cmd":{},"single_motor_vibrate_cmd":{}}}}]"#.to_owned().into()];
215 assert!(
216 possible_messages.contains(&smsg),
217 "We should receive ScanningFinished and DeviceAdded, but the order may change. Got {:?}",
218 smsg
219 );
220 msg = recv.next().await.expect("Test, assuming infallible.");
221 smsg = serializer.serialize(&vec![msg]);
222 // We should get back an aneros with only SingleMotorVibrateCmd
223 assert!(
224 possible_messages.contains(&smsg),
225 "We should receive ScanningFinished and DeviceAdded, but the order may change. Got {:?}",
226 smsg
227 );
228 let output2 = server
229 .parse_message(
230 serializer
231 .deserialize(
232 &r#"[{"VibrateCmd": { "Id": 2, "DeviceIndex": 0, "Speeds": [{ "Index": 0, "Speed": 0.5 }]}}]"#
233 .to_owned()
234 .into(),
235 )
236 .expect("Test, assuming infallible.")[0]
237 .clone(),
238 )
239 .await
240 .expect("Test, assuming infallible.");
241 assert_eq!(
242 serializer.serialize(&vec!(output2)),
243 r#"[{"Ok":{"Id":2}}]"#.to_owned().into()
244 );
245 check_test_recv_value(
246 &Duration::from_millis(150),
247 &mut device,
248 HardwareCommand::Write(HardwareWriteCmd::new(
249 &[Uuid::nil()],
250 Endpoint::Tx,
251 vec![0xF1, 64],
252 false,
253 )),
254 )
255 .await;
256}
257
258#[tokio::test]
259async fn test_version0_oscillatoronly() {
260 let (server, mut _device) = test_server_with_device("Xone");
261 let recv = server.event_stream();
262 pin_mut!(recv);
263 let serializer = ButtplugServerJSONSerializer::default();
264 let rsi = r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client"}}]"#;
265 let output = server
266 .parse_message(
267 serializer
268 .deserialize(&rsi.to_owned().into())
269 .expect("Test, assuming infallible.")[0]
270 .clone(),
271 )
272 .await
273 .expect("Test, assuming infallible.");
274 assert_eq!(
275 serializer.serialize(&vec!(output)),
276 r#"[{"ServerInfo":{"Id":1,"MajorVersion":0,"MinorVersion":0,"BuildVersion":0,"MessageVersion":0,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
277 );
278 // Skip JSON parsing here, we aren't converting versions.
279 let reply = server
280 .parse_message(ButtplugClientMessageVariant::V0(
281 StartScanningV0::default().into(),
282 ))
283 .await;
284 assert!(reply.is_ok(), "Should get back ok: {:?}", reply);
285 // Check that we got an event back about scanning finishing.
286 let mut msg = recv.next().await.expect("Test, assuming infallible.");
287 let mut smsg = serializer.serialize(&vec![msg]);
288 // We should receive ScanningFinished and DeviceAdded, but the order may change.
289 let possible_messages: Vec<ButtplugSerializedMessage> = vec![r#"[{"ScanningFinished":{"Id":0}}]"#.to_owned().into(), r#"[{"DeviceAdded":{"Id":0,"DeviceIndex":0,"DeviceName":"MagicMotion Xone","DeviceMessages":["StopDeviceCmd"]}}]"#.to_owned().into()];
290 assert!(
291 possible_messages.contains(&smsg),
292 "We should receive ScanningFinished and DeviceAdded, but the order may change. Got {:?}",
293 smsg
294 );
295 msg = recv.next().await.expect("Test, assuming infallible.");
296 smsg = serializer.serialize(&vec![msg]);
297 // We should get back an MagicMotion Xone with no actuators
298 assert!(
299 possible_messages.contains(&smsg),
300 "We should receive ScanningFinished and DeviceAdded, but the order may change. Got {:?}",
301 smsg
302 );
303}
304
305#[tokio::test]
306async fn test_version1_oscilatoronly() {
307 let (server, mut _device) = test_server_with_device("Xone");
308 let recv = server.event_stream();
309 pin_mut!(recv);
310 let serializer = ButtplugServerJSONSerializer::default();
311 let rsi =
312 r#"[{"RequestServerInfo":{"Id": 1, "ClientName": "Test Client", "MessageVersion": 1}}]"#;
313 let output = server
314 .parse_message(
315 serializer
316 .deserialize(&rsi.to_owned().into())
317 .expect("Test, assuming infallible.")[0]
318 .clone(),
319 )
320 .await
321 .expect("Test, assuming infallible.");
322 assert_eq!(
323 serializer.serialize(&vec!(output)),
324 r#"[{"ServerInfo":{"Id":1,"MajorVersion":0,"MinorVersion":0,"BuildVersion":0,"MessageVersion":1,"MaxPingTime":0,"ServerName":"Buttplug Server"}}]"#.to_owned().into(),
325 );
326 // Skip JSON parsing here, we aren't converting versions.
327 let reply = server
328 .parse_message(ButtplugClientMessageVariant::V1(
329 StartScanningV0::default().into(),
330 ))
331 .await;
332 assert!(reply.is_ok(), "Should get back ok: {:?}", reply);
333 // Check that we got an event back about scanning finishing.
334 let mut msg = recv.next().await.expect("Test, assuming infallible.");
335 let mut smsg = serializer.serialize(&vec![msg]);
336 // We should receive ScanningFinished and DeviceAdded, but the order may change.
337 let possible_messages: Vec<ButtplugSerializedMessage> = vec![r#"[{"ScanningFinished":{"Id":0}}]"#.to_owned().into(), r#"[{"DeviceAdded":{"Id":0,"DeviceIndex":0,"DeviceName":"MagicMotion Xone","DeviceMessages":{"stop_device_cmd":{}}}}]"#.to_owned().into()];
338 assert!(
339 possible_messages.contains(&smsg),
340 "We should receive ScanningFinished and DeviceAdded, but the order may change. Got {:?}",
341 smsg
342 );
343 msg = recv.next().await.expect("Test, assuming infallible.");
344 smsg = serializer.serialize(&vec![msg]);
345 // We should get back an MagicMotion Xone with no actuators
346 assert!(
347 possible_messages.contains(&smsg),
348 "We should receive ScanningFinished and DeviceAdded, but the order may change. Got {:?}",
349 smsg
350 );
351}