| // Copyright 2023 Google LLC | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | use std::task::Poll; | 
 |  | 
 | use assert_matches::assert_matches; | 
 | use futures::{Future, FutureExt, StreamExt}; | 
 |  | 
 | use bt_common::{PeerId, Uuid}; | 
 |  | 
 | use crate::test_utils::*; | 
 | use crate::types::*; | 
 | use crate::{central::Filter, client::PeerService, Central}; | 
 |  | 
 | const TEST_UUID_1: Uuid = Uuid::from_u16(0x1234); | 
 | const TEST_UUID_2: Uuid = Uuid::from_u16(0x2345); | 
 | const TEST_UUID_3: Uuid = Uuid::from_u16(0x3456); | 
 |  | 
 | // Sets up a fake peer service with some characteristics. | 
 | fn set_up() -> FakePeerService { | 
 |     let mut fake_peer_service = FakePeerService::new(); | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(1), | 
 |             uuid: TEST_UUID_1, | 
 |             properties: CharacteristicProperties(vec![ | 
 |                 CharacteristicProperty::Broadcast, | 
 |                 CharacteristicProperty::Notify, | 
 |             ]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![], | 
 |     ); | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(2), | 
 |             uuid: TEST_UUID_1, | 
 |             properties: CharacteristicProperties(vec![ | 
 |                 CharacteristicProperty::Broadcast, | 
 |                 CharacteristicProperty::Notify, | 
 |             ]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![], | 
 |     ); | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(3), | 
 |             uuid: TEST_UUID_1, | 
 |             properties: CharacteristicProperties(vec![ | 
 |                 CharacteristicProperty::Broadcast, | 
 |                 CharacteristicProperty::Notify, | 
 |             ]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![], | 
 |     ); | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(4), | 
 |             uuid: TEST_UUID_2, | 
 |             properties: CharacteristicProperties(vec![CharacteristicProperty::Notify]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![], | 
 |     ); | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(5), | 
 |             uuid: TEST_UUID_3, | 
 |             properties: CharacteristicProperties(vec![CharacteristicProperty::Broadcast]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![], | 
 |     ); | 
 |     fake_peer_service | 
 | } | 
 |  | 
 | #[test] | 
 | fn peer_service_discover_characteristics_works() { | 
 |     let mut noop_cx = futures::task::Context::from_waker(futures::task::noop_waker_ref()); | 
 |  | 
 |     let fake_peer_service = set_up(); | 
 |  | 
 |     let mut discover_results = fake_peer_service.discover_characteristics(Some(TEST_UUID_1)); | 
 |     let polled = discover_results.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Ok(chars)) => { assert_eq!(chars.len(), 3) }); | 
 |  | 
 |     let mut discover_results = fake_peer_service.discover_characteristics(Some(TEST_UUID_2)); | 
 |     let polled = discover_results.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Ok(chars)) => { assert_eq!(chars.len(), 1) }); | 
 |  | 
 |     let mut discover_results = | 
 |         fake_peer_service.discover_characteristics(Some(Uuid::from_u16(0xFF22))); | 
 |     let polled = discover_results.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Ok(chars)) => { assert_eq!(chars.len(), 0) }); | 
 |  | 
 |     let mut discover_results = fake_peer_service.discover_characteristics(None); | 
 |     let polled = discover_results.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Ok(chars)) => { assert_eq!(chars.len(), 5) }); | 
 | } | 
 |  | 
 | #[test] | 
 | fn peer_service_read_characteristic() { | 
 |     let mut noop_cx = futures::task::Context::from_waker(futures::task::noop_waker_ref()); | 
 |  | 
 |     let mut fake_peer_service = set_up(); | 
 |     let mut buf = vec![0; 255]; | 
 |  | 
 |     // For characteristic that was added, value is returned | 
 |     let mut read_result = fake_peer_service.read_characteristic(&Handle(0x1), 0, &mut buf[..]); | 
 |     let polled: Poll<std::prelude::v1::Result<(usize, bool), Error>> = | 
 |         read_result.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Ok((len, _))) => { assert_eq!(len, 0) }); | 
 |  | 
 |     // For characteristic that doesn't exist, fails. | 
 |     let mut read_result = fake_peer_service.read_characteristic(&Handle(0xF), 0, &mut buf[..]); | 
 |     let polled = read_result.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Err(_))); | 
 |  | 
 |     // Change the value for characteristic with handle 1. | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(1), | 
 |             uuid: TEST_UUID_1, | 
 |             properties: CharacteristicProperties(vec![ | 
 |                 CharacteristicProperty::Broadcast, | 
 |                 CharacteristicProperty::Notify, | 
 |             ]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![0, 1, 2, 3], | 
 |     ); | 
 |  | 
 |     // Successfully reads the updated value. | 
 |     let mut read_result = fake_peer_service.read_characteristic(&Handle(0x1), 0, &mut buf[..]); | 
 |     let polled = read_result.poll_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Ok((len, _))) => { | 
 |         assert_eq!(len, 4); | 
 |         assert_eq!(buf[..len], vec![0,1,2,3]); | 
 |     }); | 
 | } | 
 |  | 
 | #[test] | 
 | fn peer_service_subsribe() { | 
 |     let mut noop_cx = futures::task::Context::from_waker(futures::task::noop_waker_ref()); | 
 |  | 
 |     let mut fake_peer_service = set_up(); | 
 |     let mut notification_stream = fake_peer_service.subscribe(&Handle(0x1)); | 
 |  | 
 |     // Stream is empty unless we add an item through the FakeNotificationStream | 
 |     // struct. | 
 |     assert!(notification_stream.poll_next_unpin(&mut noop_cx).is_pending()); | 
 |  | 
 |     // Update the characteristic value so that notification is sent. | 
 |     fake_peer_service.add_characteristic( | 
 |         Characteristic { | 
 |             handle: Handle(1), | 
 |             uuid: TEST_UUID_1, | 
 |             properties: CharacteristicProperties(vec![ | 
 |                 CharacteristicProperty::Broadcast, | 
 |                 CharacteristicProperty::Notify, | 
 |             ]), | 
 |             permissions: AttributePermissions::default(), | 
 |             descriptors: vec![], | 
 |         }, | 
 |         vec![0, 1, 2, 3], | 
 |     ); | 
 |  | 
 |     // Stream should be ready. | 
 |     let polled = notification_stream.poll_next_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Some(Ok(notification))) => { | 
 |         assert_eq!(notification.handle, Handle(0x1)); | 
 |         assert_eq!(notification.value, vec![0,1,2,3]); | 
 |         assert_eq!(notification.maybe_truncated, false); | 
 |     }); | 
 |  | 
 |     assert!(notification_stream.poll_next_unpin(&mut noop_cx).is_pending()); | 
 | } | 
 |  | 
 | #[test] | 
 | fn central_search_works() { | 
 |     let mut noop_cx = futures::task::Context::from_waker(futures::task::noop_waker_ref()); | 
 |     let central = FakeCentral::default(); | 
 |  | 
 |     let mut scan_results = central.scan(&[Filter::ServiceUuid(Uuid::from_u16(0x1844)).into()]); | 
 |  | 
 |     let polled = scan_results.poll_next_unpin(&mut noop_cx); | 
 |     assert_matches!(polled, Poll::Ready(Some(Ok(_)))); | 
 | } | 
 |  | 
 | fn boxed_generic_usage<T: crate::GattTypes>(central: Box<dyn crate::Central<T>>) { | 
 |     use crate::client::PeerServiceHandle; | 
 |  | 
 |     let mut noop_cx = futures::task::Context::from_waker(futures::task::noop_waker_ref()); | 
 |     let _stream = central.scan(&[]); | 
 |     let connect_fut = central.connect(PeerId(1)); | 
 |  | 
 |     futures::pin_mut!(connect_fut); | 
 |     let Poll::Ready(Ok(client)) = connect_fut.poll(&mut noop_cx) else { | 
 |         panic!("Connect should be ready Ok"); | 
 |     }; | 
 |  | 
 |     let client_boxed: Box<dyn crate::client::Client<T>> = Box::new(client); | 
 |  | 
 |     let find_serv_fut = client_boxed.find_service(Uuid::from_u16(0)); | 
 |  | 
 |     futures::pin_mut!(find_serv_fut); | 
 |     let Poll::Ready(Ok(services)) = find_serv_fut.poll(&mut noop_cx) else { | 
 |         panic!("Expected services future to resolve"); | 
 |     }; | 
 |  | 
 |     assert_eq!(services.len(), 1); | 
 |  | 
 |     let connect_service_fut = services[0].connect(); | 
 |  | 
 |     futures::pin_mut!(connect_service_fut); | 
 |     let Poll::Ready(Ok(service)) = connect_service_fut.poll(&mut noop_cx) else { | 
 |         panic!("Expected service to connect"); | 
 |     }; | 
 |  | 
 |     let _service_box: Box<dyn crate::client::PeerService<T>> = Box::new(service); | 
 | } | 
 |  | 
 | #[test] | 
 | fn central_dynamic_usage() { | 
 |     let central: Box<dyn crate::Central<FakeTypes>> = Box::new(FakeCentral::default()); | 
 |  | 
 |     boxed_generic_usage(central); | 
 | } |