Buttplug sex toy control library
at dev 7.3 kB view raw
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 8/* 9mod util; 10use util::{test_client, test_client_with_delayed_device_manager, test_client_with_device}; 11extern crate buttplug; 12extern crate tracing; 13 14use buttplug::{ 15 client::{connector::ButtplugInProcessClientConnectorBuilder, ButtplugClient, ButtplugClientError, ButtplugClientEvent}, 16 core::{ 17 connector::{ 18 ButtplugConnector, 19 ButtplugConnectorError, 20 ButtplugConnectorResultFuture, 21 }, 22 errors::{ButtplugDeviceError, ButtplugError}, 23 message::{ButtplugClientMessageCurrent, ButtplugClientMessageV4, ButtplugServerMessageCurrent, ButtplugServerMessageV4}, 24 }, 25 server::{message::{ButtplugClientMessageVariant, ButtplugServerMessageVariant}, ButtplugServerBuilder}, 26}; 27 28use futures::{future::BoxFuture, StreamExt}; 29use std::time::Duration; 30use tokio::{sync::mpsc::Sender, time::sleep}; 31 32#[derive(Default)] 33struct ButtplugFailingConnector {} 34 35impl ButtplugConnector<ButtplugClientMessageVariant, ButtplugServerMessageVariant> 36 for ButtplugFailingConnector 37{ 38 fn connect( 39 &mut self, 40 _: Sender<ButtplugServerMessageVariant>, 41 ) -> BoxFuture<'static, Result<(), ButtplugConnectorError>> { 42 ButtplugConnectorError::ConnectorNotConnected.into() 43 } 44 45 fn disconnect(&self) -> ButtplugConnectorResultFuture { 46 ButtplugConnectorError::ConnectorNotConnected.into() 47 } 48 49 fn send(&self, _msg: ButtplugClientMessageVariant) -> ButtplugConnectorResultFuture { 50 panic!("Should never be called") 51 } 52} 53 54 55#[tokio::test] 56async fn test_failing_connection() { 57 let client = ButtplugClient::new("Test Client"); 58 assert!(client 59 .connect(ButtplugFailingConnector::default()) 60 .await 61 .is_err()); 62} 63 64 65#[tokio::test] 66async fn test_disconnect_status() { 67 let client = test_client().await; 68 assert!(client.disconnect().await.is_ok()); 69 assert!(!client.connected()); 70} 71 72 73#[tokio::test] 74async fn test_double_disconnect() { 75 let client = test_client().await; 76 assert!(client.disconnect().await.is_ok()); 77 assert!(client.disconnect().await.is_err()); 78} 79 80 81#[tokio::test] 82async fn test_connect_init() { 83 let client = test_client().await; 84 assert_eq!(client.server_name(), Some("Buttplug Server".to_owned())); 85} 86 87 88#[tokio::test] 89async fn test_client_connected_status() { 90 let client = test_client().await; 91 client 92 .disconnect() 93 .await 94 .expect("Test, assuming infallible."); 95 assert!(!client.connected()); 96} 97 98 99#[tokio::test] 100async fn test_start_scanning() { 101 let (client, _) = test_client_with_device().await; 102 assert!(client.start_scanning().await.is_ok()); 103} 104 105 106#[tokio::test] 107#[ignore = "We may want to just call this Ok now?"] 108async fn test_stop_scanning_when_not_scanning() { 109 let (client, _) = test_client_with_device().await; 110 let should_be_err = client.stop_scanning().await; 111 if let Err(ButtplugClientError::ButtplugError(bp_err)) = should_be_err { 112 assert!(matches!( 113 bp_err, 114 ButtplugError::ButtplugDeviceError(ButtplugDeviceError::DeviceScanningAlreadyStopped) 115 )); 116 } else { 117 panic!("Should've thrown error!"); 118 } 119 assert!(client.stop_scanning().await.is_err()); 120} 121 122 123#[tokio::test] 124async fn test_start_scanning_when_already_scanning() { 125 let client = test_client_with_delayed_device_manager().await; 126 assert!(client.start_scanning().await.is_ok()); 127 assert!(client.start_scanning().await.is_ok()); 128} 129 130 131#[tokio::test] 132async fn test_successive_start_scanning() { 133 let (client, _) = test_client_with_device().await; 134 assert!(client.start_scanning().await.is_ok()); 135 assert!(client.start_scanning().await.is_ok()); 136} 137 138 139#[tokio::test] 140async fn test_client_scanning_finished() { 141 let (client, _) = test_client_with_device().await; 142 let mut recv = client.event_stream(); 143 assert!(client.start_scanning().await.is_ok()); 144 assert!(matches!( 145 recv.next().await.expect("Test, assuming infallible."), 146 ButtplugClientEvent::ScanningFinished 147 )); 148} 149 150 151#[tokio::test] 152async fn test_client_ping() { 153 let server = ButtplugServerBuilder::default() 154 .max_ping_time(200) 155 .finish() 156 .expect("Test, assuming infallible."); 157 let connector = ButtplugInProcessClientConnectorBuilder::default() 158 .server(server) 159 .finish(); 160 let client = ButtplugClient::new("Test Client"); 161 client 162 .connect(connector) 163 .await 164 .expect("Test, assuming infallible."); 165 assert!(client.ping().await.is_ok()); 166 sleep(Duration::from_millis(800)).await; 167 // TODO Watch for ping events 168 assert!(client.ping().await.is_err()); 169} 170/* 171// Tests both the stop all devices functionality, as well as both ends of the 172// command range for is_in_command_range message validation. 173 174#[tokio::test] 175async fn test_stop_all_devices_and_device_command_range() { 176 let (client, test_device) = test_client_with_device().await; 177 let mut event_stream = client.event_stream(); 178 assert!(client.start_scanning().await.is_ok()); 179 180 while let Some(event) = event_stream.next().await { 181 if let ButtplugClientEvent::DeviceAdded(dev) = event { 182 info!("{:?}", dev.vibrate(ScalarCommand::Scalar(0.5)).await); 183 assert!(dev.vibrate(ScalarCommand::Scalar(0.5)).await.is_ok()); 184 // Unlike protocol unit tests, here the endpoint doesn't exist until 185 // after device creation, so create the test receiver later. 186 let command_receiver = test_device 187 .endpoint_receiver(&Endpoint::Tx) 188 .expect("Test, assuming infallible."); 189 check_test_recv_value( 190 &command_receiver, 191 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF1, 64], false)), 192 ); 193 check_test_recv_value( 194 &command_receiver, 195 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF2, 64], false)), 196 ); 197 assert!(dev.vibrate(ScalarCommand::Scalar(1.0)).await.is_ok()); 198 check_test_recv_value( 199 &command_receiver, 200 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF1, 127], false)), 201 ); 202 check_test_recv_value( 203 &command_receiver, 204 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF2, 127], false)), 205 ); 206 assert!(client.stop_all_devices().await.is_ok()); 207 check_test_recv_value( 208 &command_receiver, 209 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF1, 0], false)), 210 ); 211 check_test_recv_value( 212 &command_receiver, 213 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF2, 0], false)), 214 ); 215 break; 216 } 217 } 218 assert!(client.stop_all_devices().await.is_ok()); 219} 220*/ 221// TODO Test calling connect twice 222// TODO Test calling disconnect twice w/o connection 223// TODO Test invalid return on RequestServerInfo 224// TODO Test invalid return on DeviceList 225// TODO Test receiving unmatched Ok (should emit error) 226// TODO Test receiving unmatched DeviceRemoved 227// TODO Test receiving Error when expecting Ok (i.e. StartScanning returns an error) 228// TODO Test receiving wrong message expecting Ok (i.e. StartScanning returns DeviceList) 229*/