1 // Copyright 2024 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 #include "pw_bluetooth_proxy/h4_packet.h"
16
17 #include <cstdint>
18
19 #include "lib/stdcompat/utility.h"
20 #include "pw_bluetooth/hci_h4.emb.h"
21 #include "pw_unit_test/framework.h" // IWYU pragma: keep
22
23 namespace pw::bluetooth::proxy {
24
25 namespace {
26
TEST(H4Packet,H4PacketWithHciGets)27 TEST(H4Packet, H4PacketWithHciGets) {
28 std::array<uint8_t, 5> hci_buffer{0, 1, 2, 3, 4};
29 H4PacketWithHci packet{emboss::H4PacketType::COMMAND, pw::span{hci_buffer}};
30
31 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::COMMAND);
32
33 EXPECT_EQ(packet.GetHciSpan().size(), hci_buffer.size());
34 EXPECT_EQ(packet.GetHciSpan().data(), hci_buffer.data());
35 }
36
TEST(H4Packet,H4PacketWithHciSets)37 TEST(H4Packet, H4PacketWithHciSets) {
38 std::array<uint8_t, 5> hci_buffer{0, 1, 2, 3, 4};
39 H4PacketWithHci packet{emboss::H4PacketType::COMMAND, pw::span{hci_buffer}};
40
41 packet.SetH4Type(emboss::H4PacketType::EVENT);
42
43 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::EVENT);
44 }
45
TEST(H4Packet,H4PacketWithH4Gets)46 TEST(H4Packet, H4PacketWithH4Gets) {
47 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
48 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
49 H4PacketWithH4 packet{pw::span{h4_buffer}};
50
51 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::COMMAND);
52
53 EXPECT_EQ(packet.GetH4Span().size(), h4_buffer.size());
54 EXPECT_EQ(packet.GetH4Span().data(), h4_buffer.data());
55
56 // HCI span should be h4 buffer without the first byte.
57 EXPECT_EQ(packet.GetHciSpan().size(), h4_buffer.size() - 1);
58 EXPECT_EQ(packet.GetHciSpan().data(), h4_buffer.data() + 1);
59
60 EXPECT_FALSE(packet.HasReleaseFn());
61 }
62
TEST(H4Packet,H4PacketWithTypeCtorWithH4Gets)63 TEST(H4Packet, H4PacketWithTypeCtorWithH4Gets) {
64 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
65 H4PacketWithH4 packet{emboss::H4PacketType::COMMAND, pw::span{h4_buffer}};
66
67 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::COMMAND);
68
69 EXPECT_EQ(packet.GetH4Span().size(), h4_buffer.size());
70 EXPECT_EQ(packet.GetH4Span().data(), h4_buffer.data());
71
72 // HCI span should be h4 buffer without the first byte.
73 EXPECT_EQ(packet.GetHciSpan().size(), h4_buffer.size() - 1);
74 EXPECT_EQ(packet.GetHciSpan().data(), h4_buffer.data() + 1);
75
76 EXPECT_FALSE(packet.HasReleaseFn());
77 }
78
TEST(H4Packet,H4PacketWithH4WithEmptyBuffer)79 TEST(H4Packet, H4PacketWithH4WithEmptyBuffer) {
80 std::array<uint8_t, 0> h4_buffer{};
81 H4PacketWithH4 packet{pw::span{h4_buffer}};
82
83 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
84
85 EXPECT_TRUE(packet.GetH4Span().empty());
86
87 EXPECT_TRUE(packet.GetHciSpan().empty());
88
89 EXPECT_FALSE(packet.HasReleaseFn());
90 }
91
TEST(H4Packet,H4PacketWithWithTypeCtorWithEmptyBuffer)92 TEST(H4Packet, H4PacketWithWithTypeCtorWithEmptyBuffer) {
93 std::array<uint8_t, 0> h4_buffer{};
94 H4PacketWithH4 packet{emboss::H4PacketType::COMMAND, pw::span{h4_buffer}};
95
96 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
97
98 EXPECT_TRUE(packet.GetH4Span().empty());
99
100 EXPECT_TRUE(packet.GetHciSpan().empty());
101
102 EXPECT_FALSE(packet.HasReleaseFn());
103 }
104
TEST(H4Packet,H4PacketWithH4Sets)105 TEST(H4Packet, H4PacketWithH4Sets) {
106 std::array<uint8_t, 5> h4_buffer = {0, 1, 2, 3, 4};
107 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
108 H4PacketWithH4 packet{pw::span{h4_buffer}};
109
110 packet.SetH4Type(emboss::H4PacketType::EVENT);
111
112 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::EVENT);
113 EXPECT_EQ(h4_buffer[0], cpp23::to_underlying(emboss::H4PacketType::EVENT));
114 }
115
TEST(H4PacketRelease,EmptyReleaseFn)116 TEST(H4PacketRelease, EmptyReleaseFn) {
117 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
118 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
119
120 H4PacketWithH4 packet(pw::span{h4_buffer});
121 EXPECT_FALSE(packet.HasReleaseFn());
122
123 H4PacketWithH4 packet2(emboss::H4PacketType::EVENT, pw::span{h4_buffer});
124 EXPECT_FALSE(packet2.HasReleaseFn());
125
126 H4PacketWithH4 packet3(pw::span{h4_buffer}, nullptr);
127 EXPECT_FALSE(packet3.HasReleaseFn());
128 }
129
TEST(H4PacketRelease,ReleaseCalledOnDtor)130 TEST(H4PacketRelease, ReleaseCalledOnDtor) {
131 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
132 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
133
134 const uint8_t* released_h4_buffer = nullptr;
135 {
136 H4PacketWithH4 packet{
137 pw::span{h4_buffer},
138 [&released_h4_buffer](const uint8_t* h4_buffer_to_release) {
139 released_h4_buffer = h4_buffer_to_release;
140 }};
141 EXPECT_TRUE(packet.HasReleaseFn());
142 }
143
144 // release_fn was called with h4_buffer* by the time packet went out of scope
145 EXPECT_TRUE(released_h4_buffer);
146 EXPECT_EQ(released_h4_buffer, h4_buffer.data());
147 }
148
TEST(H4PacketRelease,ReleaseCalledAfterMoveOnDtor)149 TEST(H4PacketRelease, ReleaseCalledAfterMoveOnDtor) {
150 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
151 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
152
153 const uint8_t* released_h4_buffer = nullptr;
154 {
155 H4PacketWithH4 packet{
156 pw::span{h4_buffer},
157 [&released_h4_buffer](const uint8_t* h4_buffer_to_release) {
158 released_h4_buffer = h4_buffer_to_release;
159 }};
160
161 EXPECT_TRUE(packet.HasReleaseFn());
162
163 H4PacketWithH4 packet2(std::move(packet));
164
165 // packet was reset by packet2 move
166 // NOLINTNEXTLINE(bugprone-use-after-move)
167 EXPECT_FALSE(packet.HasReleaseFn());
168 EXPECT_TRUE(packet.GetHciSpan().empty());
169 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
170
171 // release_fn was not called during move
172 EXPECT_EQ(released_h4_buffer, nullptr);
173 }
174
175 // release_fn was called with h4_buffer* by the time packet2 went out of scope
176 EXPECT_NE(released_h4_buffer, nullptr);
177 EXPECT_EQ(released_h4_buffer, h4_buffer.data());
178 }
179
TEST(H4PacketRelease,ReleaseCalledAfterMoveAssignOnDtor)180 TEST(H4PacketRelease, ReleaseCalledAfterMoveAssignOnDtor) {
181 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
182 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
183
184 const uint8_t* released_h4_buffer = nullptr;
185 {
186 H4PacketWithH4 packet{
187 pw::span{h4_buffer},
188 [&released_h4_buffer](const uint8_t* h4_buffer_to_release) {
189 released_h4_buffer = h4_buffer_to_release;
190 }};
191
192 EXPECT_TRUE(packet.HasReleaseFn());
193
194 H4PacketWithH4 packet2{{}};
195 packet2 = std::move(packet);
196
197 // packet was reset by packet2 move assign
198 // NOLINTNEXTLINE(bugprone-use-after-move)
199 EXPECT_FALSE(packet.HasReleaseFn());
200 EXPECT_TRUE(packet.GetHciSpan().empty());
201 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
202
203 // release_fn was not called during move assign
204 EXPECT_EQ(released_h4_buffer, nullptr);
205 }
206
207 // release_fn was called with h4_buffer* by the time packet2 went out of scope
208 EXPECT_NE(released_h4_buffer, nullptr);
209 EXPECT_EQ(released_h4_buffer, h4_buffer.data());
210 }
211
TEST(H4PacketRelease,ResetAndReturnReleaseFn)212 TEST(H4PacketRelease, ResetAndReturnReleaseFn) {
213 std::array<uint8_t, 5> h4_buffer{0, 1, 2, 3, 4};
214 h4_buffer[0] = cpp23::to_underlying(emboss::H4PacketType::COMMAND);
215
216 const uint8_t* released_h4_buffer = nullptr;
217 {
218 H4PacketWithH4 packet{
219 pw::span{h4_buffer},
220 [&released_h4_buffer](const uint8_t* h4_buffer_to_release) {
221 released_h4_buffer = h4_buffer_to_release;
222 }};
223 EXPECT_TRUE(packet.HasReleaseFn());
224
225 pw::span<uint8_t> span_from_packet = packet.GetH4Span();
226 EXPECT_FALSE(span_from_packet.empty());
227
228 pw::Function<void(const uint8_t*)> release_fn =
229 packet.ResetAndReturnReleaseFn();
230 EXPECT_TRUE(release_fn);
231
232 // packet was reset by ResetAndReturnReleaseFn
233 EXPECT_FALSE(packet.HasReleaseFn());
234 EXPECT_TRUE(packet.GetHciSpan().empty());
235 EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
236
237 // release_fn passed to packet was not called yet
238 EXPECT_EQ(released_h4_buffer, nullptr);
239
240 release_fn(span_from_packet.data());
241
242 // release_fn passed to packet and returned above was called with h4_buffer*
243 EXPECT_TRUE(released_h4_buffer);
244
245 // Set to null so we can verify outside of scope that release_fn was
246 // not called again.
247 released_h4_buffer = nullptr;
248 }
249
250 // release_fn passed to packet was not called by the time packet went out of
251 // scope
252 EXPECT_EQ(released_h4_buffer, nullptr);
253 }
254
255 } // namespace
256 } // namespace pw::bluetooth::proxy
257