xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/h4_packet_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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