use crate::expect::{expect_call, Status};
use anyhow::Error;
use fidl::endpoints::{ClientEnd, ServerEnd};
use fidl_fuchsia_bluetooth::Uuid as FidlUuid;
use fidl_fuchsia_bluetooth_gatt2::{
self as gatt2, Characteristic, CharacteristicNotifierMarker, ClientControlHandle, ClientMarker,
ClientProxy, ClientRequest, ClientRequestStream, Handle, ReadByTypeResult, RemoteServiceMarker,
RemoteServiceProxy, RemoteServiceRequest, RemoteServiceRequestStream, ServiceHandle,
};
use fuchsia_bluetooth::types::Uuid;
use zx::MonotonicDuration;
pub struct RemoteServiceMock {
stream: RemoteServiceRequestStream,
timeout: MonotonicDuration,
}
impl RemoteServiceMock {
pub fn new(
timeout: MonotonicDuration,
) -> Result<(RemoteServiceProxy, RemoteServiceMock), Error> {
let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<RemoteServiceMarker>();
Ok((proxy, RemoteServiceMock { stream, timeout }))
}
pub fn from_stream(
stream: RemoteServiceRequestStream,
timeout: MonotonicDuration,
) -> RemoteServiceMock {
RemoteServiceMock { stream, timeout }
}
pub async fn expect_discover_characteristics(
&mut self,
characteristics: &Vec<Characteristic>,
) -> Result<(), Error> {
expect_call(&mut self.stream, self.timeout, move |req| match req {
RemoteServiceRequest::DiscoverCharacteristics { responder } => {
match responder.send(characteristics) {
Ok(_) => Ok(Status::Satisfied(())),
Err(e) => Err(e.into()),
}
}
_ => Ok(Status::Pending),
})
.await
}
pub async fn expect_read_by_type(
&mut self,
expected_uuid: Uuid,
result: Result<&[ReadByTypeResult], gatt2::Error>,
) -> Result<(), Error> {
let expected_uuid: FidlUuid = expected_uuid.into();
expect_call(&mut self.stream, self.timeout, move |req| {
if let RemoteServiceRequest::ReadByType { uuid, responder } = req {
if uuid == expected_uuid {
responder.send(result)?;
Ok(Status::Satisfied(()))
} else {
responder.send(Err(fidl_fuchsia_bluetooth_gatt2::Error::UnlikelyError))?;
Ok(Status::Pending)
}
} else {
Ok(Status::Pending)
}
})
.await
}
pub async fn expect_register_characteristic_notifier(
&mut self,
handle: Handle,
) -> Result<ClientEnd<CharacteristicNotifierMarker>, Error> {
expect_call(&mut self.stream, self.timeout, move |req| match req {
RemoteServiceRequest::RegisterCharacteristicNotifier {
handle: h,
notifier,
responder,
} => {
if h == handle {
responder.send(Ok(()))?;
Ok(Status::Satisfied(notifier))
} else {
responder.send(Err(gatt2::Error::InvalidHandle))?;
Ok(Status::Pending)
}
}
_ => Ok(Status::Pending),
})
.await
}
}
pub struct ClientMock {
stream: ClientRequestStream,
timeout: MonotonicDuration,
}
impl ClientMock {
pub fn new(timeout: MonotonicDuration) -> Result<(ClientProxy, ClientMock), Error> {
let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<ClientMarker>();
Ok((proxy, ClientMock { stream, timeout }))
}
pub async fn expect_connect_to_service(
&mut self,
handle: ServiceHandle,
) -> Result<(ClientControlHandle, ServerEnd<RemoteServiceMarker>), Error> {
expect_call(&mut self.stream, self.timeout, move |req| match req {
ClientRequest::ConnectToService { handle: h, service, control_handle }
if h == handle =>
{
Ok(Status::Satisfied((control_handle, service)))
}
_ => Ok(Status::Pending),
})
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::timeout_duration;
use futures::join;
#[fuchsia_async::run_until_stalled(test)]
async fn test_expect_read_by_type() {
let (proxy, mut mock) =
RemoteServiceMock::new(timeout_duration()).expect("failed to create mock");
let uuid = Uuid::new16(0x180d);
let result = Ok(&[][..]);
let fidl_uuid: FidlUuid = uuid.clone().into();
let read_by_type_fut = proxy.read_by_type(&fidl_uuid);
let expect_fut = mock.expect_read_by_type(uuid, result);
let (read_by_type_result, expect_result) = join!(read_by_type_fut, expect_fut);
let _ = read_by_type_result.expect("read by type request failed");
let _ = expect_result.expect("expectation not satisfied");
}
}