1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include <pw_async/heap_dispatcher.h>
17 
18 #include <unordered_map>
19 #include <vector>
20 
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/signaling_channel.h"
22 
23 // Helper for FakeSignalingChannel::AddOutbound to add file and line numbers of
24 // the test call site that expected the command, and to reduce one level of
25 // braces in the responses. |fake_sig| should be a FakeSignalingChannel lvalue.
26 #define EXPECT_OUTBOUND_REQ(fake_sig, req_code, req_payload, ...) \
27   (fake_sig).AddOutbound(                                         \
28       __FILE__, __LINE__, req_code, req_payload, {__VA_ARGS__})
29 
30 namespace bt::l2cap::internal::testing {
31 
32 // Can be injected into internal L2CAP tests to drive fake interactions over the
33 // signaling channels with remote peers (in both directions). Expectations for
34 // inbound and outbound expected transactions are not synchronized.
35 class FakeSignalingChannel : public SignalingChannelInterface {
36  public:
37   using TransactionId = size_t;
38 
39   // Simulated response's command code and payload.
40   using Response = std::pair<Status, BufferView>;
41 
42   // |dispatcher| is the test message loop's dispatcher
43   explicit FakeSignalingChannel(pw::async::Dispatcher& pw_dispatcher);
44   ~FakeSignalingChannel() override;
45 
46   // SignalingChannelInterface overrides
47   bool SendRequest(CommandCode req_code,
48                    const ByteBuffer& payload,
49                    ResponseHandler cb) override;
50   void ServeRequest(CommandCode req_code, RequestDelegate cb) override;
51 
52   // Add an expected outbound request, which FakeSignalingChannel will respond
53   // to with the contents of |responses|. The request's contents will be
54   // expected to match |req_code| and |req_payload|. The request's response
55   // handler will be expected to handle all responses provided here.
56   // Returns a handle that can be used to provide additional responses with
57   // |ReceiveResponses|. |file| and |line| will be used to trace test failures.
58   TransactionId AddOutbound(const char* file,
59                             int line,
60                             CommandCode req_code,
61                             BufferView req_payload,
62                             std::vector<Response> responses);
63 
64   // Receive additional responses to an already received request.
65   void ReceiveResponses(TransactionId id,
66                         const std::vector<Response>& responses);
67 
68   // Simulate reception of an inbound request with |req_code| and |req_payload|,
69   // then expect a corresponding outbound response with payload |rsp_payload|.
70   void ReceiveExpect(CommandCode req_code,
71                      const ByteBuffer& req_payload,
72                      const ByteBuffer& rsp_payload);
73 
74   // Simulate reception of an inbound request with |req_code| and |req_payload|,
75   // then expect a matching rejection with the Not Understood reason.
76   void ReceiveExpectRejectNotUnderstood(CommandCode req_code,
77                                         const ByteBuffer& req_payload);
78 
79   // Simulate reception of an inbound request with |req_code| and |req_payload|,
80   // then expect a matching rejection with the Invalid Channel ID reason and the
81   // rejected IDs |local_cid| and |remote_cid|.
82   void ReceiveExpectRejectInvalidChannelId(CommandCode req_code,
83                                            const ByteBuffer& req_payload,
84                                            ChannelId local_cid,
85                                            ChannelId remote_cid);
86 
87  private:
88   // Expected outbound request and response(s) that this fake sends back
89   struct Transaction {
90     const char* const file;
91     const int line;
92     const CommandCode request_code;
93     const BufferView req_payload;
94     const std::vector<std::pair<Status, BufferView>> responses;
95 
96     // Assigned when the request is actually sent
97     SignalingChannel::ResponseHandler response_callback = nullptr;
98 
99     // Does not include responses handled in |ReceiveResponses|.
100     size_t responses_handled = 0UL;
101   };
102 
103   // Simulate reception of |responses|, calling |transaction.response_callback|
104   // on each response until it returns false. Returns the number of invocations.
105   size_t TriggerResponses(const Transaction& transaction,
106                           const std::vector<Response>& responses);
107 
108   // Test a previously-registered request handler by simulating an inbound
109   // request of |req_code| and |req_payload|. The test will assert-fail if no
110   // handler had been registered with |ServeRequest|. |fake_responder| will be
111   // generated internally based on the kind of reply that the handler is
112   // expected to send and is passed to the handler-under-test. The test will
113   // fail if no reply at all is sent.
114   void ReceiveExpectInternal(CommandCode req_code,
115                              const ByteBuffer& req_payload,
116                              Responder* fake_responder);
117 
118   // Expected outbound transactions
119   std::vector<Transaction> transactions_;
120 
121   // Index of current outbound transaction expected through SendRequest
122   size_t expected_transaction_index_ = 0UL;
123 
124   // Registered inbound request delegates
125   std::unordered_map<CommandCode, RequestDelegate> request_handlers_;
126 
127   // Test message loop dispatcher
128   pw::async::HeapDispatcher heap_dispatcher_;
129 };
130 
131 }  // namespace bt::l2cap::internal::testing
132