|  | // 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 crate::{central::ScanResult, client::CharacteristicNotification, types::*}; | 
|  |  | 
|  | use bt_common::{PeerId, Uuid}; | 
|  | use futures::{future::Ready, stream::Empty, Future, Stream}; | 
|  | use std::task::Poll; | 
|  |  | 
|  | #[derive(Default)] | 
|  | pub(crate) struct FakeCentral {} | 
|  |  | 
|  | pub(crate) struct FakePeerService {} | 
|  |  | 
|  | impl crate::client::PeerService for FakePeerService { | 
|  | type CharacteristicsFut = Ready<Result<Vec<Characteristic>>>; | 
|  | type NotificationStream = Empty<Result<CharacteristicNotification>>; | 
|  | type ReadFut<'a> = Ready<Result<(usize, bool)>>; | 
|  | type WriteFut<'a> = Ready<Result<()>>; | 
|  |  | 
|  | fn discover_characteristics(&self, _uuid: Option<Uuid>) -> Self::CharacteristicsFut { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn read_characteristic<'a>( | 
|  | &self, | 
|  | _handle: &Handle, | 
|  | _offset: u16, | 
|  | _buf: &'a mut [u8], | 
|  | ) -> Self::ReadFut<'a> { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn write_characteristic<'a>( | 
|  | &self, | 
|  | _handle: &Handle, | 
|  | _mode: WriteMode, | 
|  | _offset: u16, | 
|  | _buf: &'a [u8], | 
|  | ) -> Self::WriteFut<'a> { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn read_descriptor<'a>( | 
|  | &self, | 
|  | _handle: &Handle, | 
|  | _offset: u16, | 
|  | _buf: &'a mut [u8], | 
|  | ) -> Self::ReadFut<'a> { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn write_descriptor<'a>( | 
|  | &self, | 
|  | _handle: &Handle, | 
|  | _offset: u16, | 
|  | _buf: &'a [u8], | 
|  | ) -> Self::WriteFut<'a> { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn subscribe(&self, _handle: &Handle) -> Self::NotificationStream { | 
|  | todo!() | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) struct FakeServiceHandle {} | 
|  |  | 
|  | impl crate::client::PeerServiceHandle for FakeServiceHandle { | 
|  | type PeerServiceT = FakePeerService; | 
|  | type ConnectFut = Ready<Result<Self::PeerServiceT>>; | 
|  |  | 
|  | fn uuid(&self) -> Uuid { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn is_primary(&self) -> bool { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn connect(&self) -> Self::ConnectFut { | 
|  | todo!() | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) struct FakeClient {} | 
|  |  | 
|  | impl crate::Client for FakeClient { | 
|  | type PeerServiceHandleT = FakeServiceHandle; | 
|  | type ServiceResultFut = Ready<Result<Vec<Self::PeerServiceHandleT>>>; | 
|  |  | 
|  | fn peer_id(&self) -> PeerId { | 
|  | todo!() | 
|  | } | 
|  |  | 
|  | fn find_service(&self, _uuid: Uuid) -> Self::ServiceResultFut { | 
|  | todo!() | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) struct SingleResultStream { | 
|  | result: Option<Result<crate::central::ScanResult>>, | 
|  | } | 
|  |  | 
|  | impl Stream for SingleResultStream { | 
|  | type Item = Result<crate::central::ScanResult>; | 
|  |  | 
|  | fn poll_next( | 
|  | self: std::pin::Pin<&mut Self>, | 
|  | _cx: &mut std::task::Context<'_>, | 
|  | ) -> Poll<Option<Self::Item>> { | 
|  | if self.result.is_some() { | 
|  | Poll::Ready(self.get_mut().result.take()) | 
|  | } else { | 
|  | // Never wake up, as if we never find another result | 
|  | Poll::Pending | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) struct ClientConnectFut {} | 
|  |  | 
|  | impl Future for ClientConnectFut { | 
|  | type Output = Result<FakeClient>; | 
|  |  | 
|  | fn poll( | 
|  | self: std::pin::Pin<&mut Self>, | 
|  | _cx: &mut std::task::Context<'_>, | 
|  | ) -> Poll<Self::Output> { | 
|  | todo!() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl crate::Central for FakeCentral { | 
|  | type ScanResultStream = SingleResultStream; | 
|  |  | 
|  | type Client = FakeClient; | 
|  |  | 
|  | type ClientFut = ClientConnectFut; | 
|  |  | 
|  | fn scan(&self, _filters: &[crate::central::ScanFilter]) -> Self::ScanResultStream { | 
|  | SingleResultStream { | 
|  | result: Some(Ok(ScanResult { | 
|  | id: PeerId(1), | 
|  | connectable: true, | 
|  | name: crate::central::PeerName::CompleteName("Marie's Pixel 7 Pro".to_owned()), | 
|  | advertised: vec![crate::central::AdvertisingDatum::Services(vec![ | 
|  | Uuid::from_u16(0x1844), | 
|  | ])], | 
|  | })), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn connect(&self, _peer_id: PeerId) -> Self::ClientFut { | 
|  | todo!() | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn central_search_works() { | 
|  | use crate::Central; | 
|  | use futures::StreamExt; | 
|  |  | 
|  | let mut noop_cx = futures::task::Context::from_waker(futures::task::noop_waker_ref()); | 
|  | use crate::central::Filter; | 
|  | 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); | 
|  | let Poll::Ready(Some(Ok(_scan_result))) = polled else { | 
|  | panic!("Expected a ready scan result got {polled:?}"); | 
|  | }; | 
|  | } |