| // 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::{FutureExt, StreamExt}; | 
 |  | 
 | use bt_common::Uuid; | 
 |  | 
 | use crate::test_utils::*; | 
 | use crate::types::*; | 
 | use crate::{Central, central::Filter, client::PeerService}; | 
 |  | 
 | 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(_)))); | 
 | } |