bt_fidl_mocks/
gatt2.rs
1use crate::expect::{expect_call, Status};
6use anyhow::Error;
7use fidl::endpoints::{ClientEnd, ServerEnd};
8use fidl_fuchsia_bluetooth::Uuid as FidlUuid;
9use fidl_fuchsia_bluetooth_gatt2::{
10 self as gatt2, Characteristic, CharacteristicNotifierMarker, ClientControlHandle, ClientMarker,
11 ClientProxy, ClientRequest, ClientRequestStream, Handle, ReadByTypeResult, RemoteServiceMarker,
12 RemoteServiceProxy, RemoteServiceRequest, RemoteServiceRequestStream, ServiceHandle,
13};
14use fuchsia_bluetooth::types::Uuid;
15use zx::MonotonicDuration;
16
17pub struct RemoteServiceMock {
19 stream: RemoteServiceRequestStream,
20 timeout: MonotonicDuration,
21}
22
23impl RemoteServiceMock {
24 pub fn new(
25 timeout: MonotonicDuration,
26 ) -> Result<(RemoteServiceProxy, RemoteServiceMock), Error> {
27 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<RemoteServiceMarker>();
28 Ok((proxy, RemoteServiceMock { stream, timeout }))
29 }
30
31 pub fn from_stream(
32 stream: RemoteServiceRequestStream,
33 timeout: MonotonicDuration,
34 ) -> RemoteServiceMock {
35 RemoteServiceMock { stream, timeout }
36 }
37
38 pub async fn expect_discover_characteristics(
39 &mut self,
40 characteristics: &Vec<Characteristic>,
41 ) -> Result<(), Error> {
42 expect_call(&mut self.stream, self.timeout, move |req| match req {
43 RemoteServiceRequest::DiscoverCharacteristics { responder } => {
44 match responder.send(characteristics) {
45 Ok(_) => Ok(Status::Satisfied(())),
46 Err(e) => Err(e.into()),
47 }
48 }
49 _ => Ok(Status::Pending),
50 })
51 .await
52 }
53
54 pub async fn expect_read_by_type(
57 &mut self,
58 expected_uuid: Uuid,
59 result: Result<&[ReadByTypeResult], gatt2::Error>,
60 ) -> Result<(), Error> {
61 let expected_uuid: FidlUuid = expected_uuid.into();
62 expect_call(&mut self.stream, self.timeout, move |req| {
63 if let RemoteServiceRequest::ReadByType { uuid, responder } = req {
64 if uuid == expected_uuid {
65 responder.send(result)?;
66 Ok(Status::Satisfied(()))
67 } else {
68 responder.send(Err(fidl_fuchsia_bluetooth_gatt2::Error::UnlikelyError))?;
70 Ok(Status::Pending)
71 }
72 } else {
73 Ok(Status::Pending)
74 }
75 })
76 .await
77 }
78
79 pub async fn expect_register_characteristic_notifier(
80 &mut self,
81 handle: Handle,
82 ) -> Result<ClientEnd<CharacteristicNotifierMarker>, Error> {
83 expect_call(&mut self.stream, self.timeout, move |req| match req {
84 RemoteServiceRequest::RegisterCharacteristicNotifier {
85 handle: h,
86 notifier,
87 responder,
88 } => {
89 if h == handle {
90 responder.send(Ok(()))?;
91 Ok(Status::Satisfied(notifier))
92 } else {
93 responder.send(Err(gatt2::Error::InvalidHandle))?;
94 Ok(Status::Pending)
95 }
96 }
97 _ => Ok(Status::Pending),
98 })
99 .await
100 }
101}
102
103pub struct ClientMock {
106 stream: ClientRequestStream,
107 timeout: MonotonicDuration,
108}
109
110impl ClientMock {
111 pub fn new(timeout: MonotonicDuration) -> Result<(ClientProxy, ClientMock), Error> {
112 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<ClientMarker>();
113 Ok((proxy, ClientMock { stream, timeout }))
114 }
115
116 pub async fn expect_connect_to_service(
117 &mut self,
118 handle: ServiceHandle,
119 ) -> Result<(ClientControlHandle, ServerEnd<RemoteServiceMarker>), Error> {
120 expect_call(&mut self.stream, self.timeout, move |req| match req {
121 ClientRequest::ConnectToService { handle: h, service, control_handle }
122 if h == handle =>
123 {
124 Ok(Status::Satisfied((control_handle, service)))
125 }
126 _ => Ok(Status::Pending),
127 })
128 .await
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use crate::timeout_duration;
136 use futures::join;
137
138 #[fuchsia_async::run_until_stalled(test)]
139 async fn test_expect_read_by_type() {
140 let (proxy, mut mock) =
141 RemoteServiceMock::new(timeout_duration()).expect("failed to create mock");
142 let uuid = Uuid::new16(0x180d);
143 let result = Ok(&[][..]);
144
145 let fidl_uuid: FidlUuid = uuid.clone().into();
146 let read_by_type_fut = proxy.read_by_type(&fidl_uuid);
147 let expect_fut = mock.expect_read_by_type(uuid, result);
148
149 let (read_by_type_result, expect_result) = join!(read_by_type_fut, expect_fut);
150 let _ = read_by_type_result.expect("read by type request failed");
151 let _ = expect_result.expect("expectation not satisfied");
152 }
153}