1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <base/bind_helpers.h>
19 #include <base/functional/bind.h>
20 #include <base/strings/string_number_conversions.h>
21 #include <bluetooth/log.h>
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 #include <osi/include/alarm.h>
25 #include <sys/socket.h>
26
27 #include <variant>
28
29 #include "bta/le_audio/le_audio_types.h"
30 #include "bta_csis_api.h"
31 #include "bta_gatt_api_mock.h"
32 #include "bta_gatt_queue_mock.h"
33 #include "bta_has_api.h"
34 #include "btif_storage_mock.h"
35 #include "btm_api_mock.h"
36 #include "gatt/database_builder.h"
37 #include "hardware/bt_gatt_types.h"
38 #include "has_types.h"
39 #include "mock_csis_client.h"
40 #include "stack/include/bt_uuid16.h"
41 #include "test/common/mock_functions.h"
42
gatt_profile_get_eatt_support(const RawAddress & addr)43 bool gatt_profile_get_eatt_support(const RawAddress& addr) { return true; }
44 void osi_property_set_bool(const char* key, bool value);
45
46 namespace bluetooth {
47 namespace has {
48 namespace internal {
49 namespace {
50
51 using base::HexEncode;
52
53 using ::bluetooth::csis::CsisClient;
54 using ::bluetooth::has::ConnectionState;
55 using ::bluetooth::has::ErrorCode;
56 using ::bluetooth::has::HasClientCallbacks;
57 using ::bluetooth::has::PresetInfo;
58
59 using ::bluetooth::le_audio::has::HasClient;
60 using ::bluetooth::le_audio::has::HasCtpGroupOpCoordinator;
61 using ::bluetooth::le_audio::has::HasCtpOp;
62 using ::bluetooth::le_audio::has::HasDevice;
63 using ::bluetooth::le_audio::has::HasPreset;
64
65 using ::testing::_;
66 using ::testing::AnyNumber;
67 using ::testing::DoAll;
68 using ::testing::DoDefault;
69 using ::testing::Invoke;
70 using ::testing::Mock;
71 using ::testing::NotNull;
72 using ::testing::Return;
73 using ::testing::SaveArg;
74 using ::testing::Sequence;
75 using ::testing::SetArgPointee;
76 using ::testing::WithArg;
77
78 // Disables most likely false-positives from base::SplitString()
79 // extern "C" const char* __asan_default_options() {
80 // return "detect_container_overflow=0";
81 // }
82
GetTestAddress(int index)83 RawAddress GetTestAddress(int index) {
84 EXPECT_LT(index, UINT8_MAX);
85 RawAddress result = {
86 {0xC0, 0xDE, 0xC0, 0xDE, 0x00, static_cast<uint8_t>(index)}};
87 return result;
88 }
89
GetTestConnId(const RawAddress & address)90 static uint16_t GetTestConnId(const RawAddress& address) {
91 return address.address[RawAddress::kLength - 1];
92 }
93
94 class MockHasCallbacks : public HasClientCallbacks {
95 public:
96 MockHasCallbacks() = default;
97 MockHasCallbacks(const MockHasCallbacks&) = delete;
98 MockHasCallbacks& operator=(const MockHasCallbacks&) = delete;
99
100 ~MockHasCallbacks() override = default;
101
102 MOCK_METHOD((void), OnConnectionState,
103 (ConnectionState state, const RawAddress& address), (override));
104 MOCK_METHOD((void), OnDeviceAvailable,
105 (const RawAddress& address, uint8_t features), (override));
106 MOCK_METHOD((void), OnFeaturesUpdate,
107 (const RawAddress& address, uint8_t features), (override));
108 MOCK_METHOD((void), OnActivePresetSelected,
109 ((std::variant<RawAddress, int> addr_or_group_id),
110 uint8_t preset_index),
111 (override));
112 MOCK_METHOD((void), OnActivePresetSelectError,
113 ((std::variant<RawAddress, int> addr_or_group_id),
114 ErrorCode result),
115 (override));
116 MOCK_METHOD((void), OnPresetInfo,
117 ((std::variant<RawAddress, int> addr_or_group_id),
118 PresetInfoReason change_id,
119 std::vector<PresetInfo> preset_change_records),
120 (override));
121 MOCK_METHOD((void), OnPresetInfoError,
122 ((std::variant<RawAddress, int> addr_or_group_id),
123 uint8_t preset_index, ErrorCode error_code),
124 (override));
125 MOCK_METHOD((void), OnSetPresetNameError,
126 ((std::variant<RawAddress, int> addr_or_group_id),
127 uint8_t preset_index, ErrorCode error_code),
128 (override));
129 };
130
131 class HasClientTestBase : public ::testing::Test {
132 protected:
133 std::map<uint16_t, uint8_t> current_peer_active_preset_idx_;
134 std::map<uint16_t, uint8_t> current_peer_features_val_;
135 std::map<uint16_t, std::set<HasPreset, HasPreset::ComparatorDesc>>
136 current_peer_presets_;
137
138 struct HasDbBuilder {
139 bool has;
140
141 static constexpr uint16_t kGapSvcStartHdl = 0x0001;
142 static constexpr uint16_t kGapDeviceNameValHdl = 0x0003;
143 static constexpr uint16_t kGapSvcEndHdl = kGapDeviceNameValHdl;
144
145 static constexpr uint16_t kSvcStartHdl = 0x0010;
146 static constexpr uint16_t kFeaturesValHdl = 0x0012;
147 static constexpr uint16_t kPresetsCtpValHdl = 0x0015;
148 static constexpr uint16_t kActivePresetIndexValHdl = 0x0018;
149 static constexpr uint16_t kSvcEndHdl = 0x001E;
150
151 static constexpr uint16_t kGattSvcStartHdl = 0x0090;
152 static constexpr uint16_t kGattSvcChangedValHdl = 0x0092;
153 static constexpr uint16_t kGattSvcEndHdl = kGattSvcChangedValHdl + 1;
154
155 bool features;
156 bool features_ntf;
157
158 bool preset_cp;
159 bool preset_cp_ntf;
160 bool preset_cp_ind;
161
162 bool active_preset_idx;
163 bool active_preset_idx_ntf;
164
Buildbluetooth::has::internal::__anonfc23c1c00111::HasClientTestBase::HasDbBuilder165 const gatt::Database Build() {
166 gatt::DatabaseBuilder bob;
167
168 /* Generic Access Service */
169 bob.AddService(kGapSvcStartHdl, kGapSvcEndHdl, Uuid::From16Bit(0x1800),
170 true);
171 /* Device Name Char. */
172 bob.AddCharacteristic(kGapDeviceNameValHdl - 1, kGapDeviceNameValHdl,
173 Uuid::From16Bit(0x2a00), GATT_CHAR_PROP_BIT_READ);
174
175 /* 0x0004-0x000f left empty on purpose */
176 if (has) {
177 bob.AddService(kSvcStartHdl, kSvcEndHdl,
178 ::bluetooth::le_audio::has::kUuidHearingAccessService,
179 true);
180
181 if (features) {
182 bob.AddCharacteristic(
183 kFeaturesValHdl - 1, kFeaturesValHdl,
184 ::bluetooth::le_audio::has::kUuidHearingAidFeatures,
185 GATT_CHAR_PROP_BIT_READ |
186 (features_ntf ? GATT_CHAR_PROP_BIT_NOTIFY : 0));
187
188 if (features_ntf) {
189 bob.AddDescriptor(kFeaturesValHdl + 1,
190 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
191 }
192 }
193
194 if (preset_cp) {
195 bob.AddCharacteristic(
196 kPresetsCtpValHdl - 1, kPresetsCtpValHdl,
197 ::bluetooth::le_audio::has::kUuidHearingAidPresetControlPoint,
198 GATT_CHAR_PROP_BIT_WRITE |
199 (preset_cp_ntf ? GATT_CHAR_PROP_BIT_NOTIFY : 0) |
200 (preset_cp_ind ? GATT_CHAR_PROP_BIT_INDICATE : 0));
201
202 if (preset_cp_ntf || preset_cp_ind) {
203 bob.AddDescriptor(kPresetsCtpValHdl + 1,
204 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
205 }
206 }
207
208 if (active_preset_idx) {
209 bob.AddCharacteristic(
210 kActivePresetIndexValHdl - 1, kActivePresetIndexValHdl,
211 ::bluetooth::le_audio::has::kUuidActivePresetIndex,
212 GATT_CHAR_PROP_BIT_READ |
213 (active_preset_idx_ntf ? GATT_CHAR_PROP_BIT_NOTIFY : 0));
214
215 if (active_preset_idx_ntf)
216 bob.AddDescriptor(kActivePresetIndexValHdl + 1,
217 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
218 }
219 }
220
221 /* GATTS */
222 /* 0x001F-0x0090 left empty on purpose */
223 bob.AddService(kGattSvcStartHdl, kGattSvcEndHdl,
224 Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER), true);
225 bob.AddCharacteristic(kGattSvcChangedValHdl - 1, kGattSvcChangedValHdl,
226 Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD),
227 GATT_CHAR_PROP_BIT_NOTIFY);
228 bob.AddDescriptor(kGattSvcChangedValHdl + 1,
229 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
230 return bob.Build();
231 };
232 };
233
FindCharacteristicByValueHandle(const gatt::Service * svc,uint16_t handle)234 const gatt::Characteristic* FindCharacteristicByValueHandle(
235 const gatt::Service* svc, uint16_t handle) {
236 if (svc == nullptr) return nullptr;
237
238 auto it =
239 std::find_if(svc->characteristics.cbegin(), svc->characteristics.cend(),
240 [handle](const auto& characteristic) {
241 return characteristic.value_handle == handle;
242 });
243 return (it != svc->characteristics.cend()) ? &(*it) : nullptr;
244 }
245
set_sample_database(const RawAddress & address,HasDbBuilder & builder,uint8_t features_val=0x0,std::optional<std::set<HasPreset,HasPreset::ComparatorDesc>> presets_op=std::nullopt)246 void set_sample_database(
247 const RawAddress& address, HasDbBuilder& builder,
248 uint8_t features_val = 0x0,
249 std::optional<std::set<HasPreset, HasPreset::ComparatorDesc>> presets_op =
250 std::nullopt) {
251 uint16_t conn_id = GetTestConnId(address);
252
253 /* For some test cases these defaults are enough */
254 if (!presets_op)
255 presets_op = {{
256 HasPreset(6, HasPreset::kPropertyAvailable, "Universal"),
257 HasPreset(
258 55, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
259 "YourPreset55"),
260 }};
261 auto& presets = presets_op.value();
262 auto const active_preset = presets.begin();
263
264 services_map[conn_id] = builder.Build().Services();
265 current_peer_features_val_.insert_or_assign(conn_id, features_val);
266 current_peer_active_preset_idx_.insert_or_assign(conn_id,
267 active_preset->GetIndex());
268 current_peer_presets_.insert_or_assign(conn_id, std::move(presets));
269
270 ON_CALL(gatt_queue, ReadCharacteristic(conn_id, _, _, _))
271 .WillByDefault(Invoke([this](uint16_t conn_id, uint16_t handle,
272 GATT_READ_OP_CB cb, void* cb_data) {
273 auto* svc = gatt::FindService(services_map[conn_id], handle);
274 if (svc == nullptr) return;
275
276 std::vector<uint8_t> value;
277 tGATT_STATUS status = GATT_SUCCESS;
278
279 switch (handle) {
280 case HasDbBuilder::kGapDeviceNameValHdl:
281 value.resize(20);
282 break;
283 case HasDbBuilder::kFeaturesValHdl:
284 value.resize(1);
285 value[0] = current_peer_features_val_.at(conn_id);
286 break;
287 case HasDbBuilder::kActivePresetIndexValHdl:
288 value.resize(1);
289 value[0] = current_peer_active_preset_idx_.at(conn_id);
290 break;
291 case HasDbBuilder::kPresetsCtpValHdl:
292 /* passthrough */
293 default:
294 status = GATT_READ_NOT_PERMIT;
295 break;
296 }
297
298 if (cb)
299 cb(conn_id, status, handle, value.size(), value.data(), cb_data);
300 }));
301
302 /* Default action for the Control Point operation writes */
303 ON_CALL(gatt_queue,
304 WriteCharacteristic(conn_id, HasDbBuilder::kPresetsCtpValHdl, _,
305 GATT_WRITE, _, _))
306 .WillByDefault(Invoke([this, address](uint16_t conn_id, uint16_t handle,
307 std::vector<uint8_t> value,
308 tGATT_WRITE_TYPE write_type,
309 GATT_WRITE_OP_CB cb,
310 void* cb_data) {
311 auto pp = value.data();
312 auto len = value.size();
313 uint8_t op, index, num_of_indices;
314
315 const bool indicate = false;
316
317 if (len < 1) {
318 if (cb)
319 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
320 value.data(), cb_data);
321 return;
322 }
323
324 STREAM_TO_UINT8(op, pp)
325 --len;
326 if (op > static_cast<std::underlying_type_t<
327 ::bluetooth::le_audio::has::PresetCtpOpcode>>(
328 ::bluetooth::le_audio::has::PresetCtpOpcode::OP_MAX_)) {
329 /* Invalid Opcode */
330 if (cb)
331 cb(conn_id, (tGATT_STATUS)0x80, handle, value.size(),
332 value.data(), cb_data);
333 return;
334 }
335
336 switch (
337 static_cast<::bluetooth::le_audio::has::PresetCtpOpcode>(op)) {
338 case ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESETS:
339 if (len < 2) {
340 if (cb)
341 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
342 value.data(), cb_data);
343
344 } else {
345 STREAM_TO_UINT8(index, pp);
346 STREAM_TO_UINT8(num_of_indices, pp);
347 len -= 2;
348 ASSERT_EQ(0u, len);
349
350 InjectNotifyReadPresetsResponse(conn_id, address, handle, value,
351 indicate, index, num_of_indices,
352 cb, cb_data);
353 }
354 break;
355
356 case ::bluetooth::le_audio::has::PresetCtpOpcode::
357 SET_ACTIVE_PRESET: {
358 if (len < 1) {
359 if (cb)
360 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
361 value.data(), cb_data);
362 break;
363 }
364 STREAM_TO_UINT8(index, pp);
365 --len;
366 ASSERT_EQ(0u, len);
367
368 auto presets = current_peer_presets_.at(conn_id);
369 if (presets.count(index)) {
370 current_peer_active_preset_idx_.insert_or_assign(conn_id,
371 index);
372 if (cb)
373 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
374 cb_data);
375 InjectActivePresetNotification(conn_id, address, handle, value,
376 index, cb, cb_data);
377 } else {
378 /* Preset Operation Not Possible */
379 if (cb)
380 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
381 value.data(), cb_data);
382 }
383 } break;
384
385 case ::bluetooth::le_audio::has::PresetCtpOpcode::
386 SET_ACTIVE_PRESET_SYNC: {
387 auto features = current_peer_features_val_.at(conn_id);
388 if ((features & ::bluetooth::has::
389 kFeatureBitPresetSynchronizationSupported) ==
390 0) {
391 /* Synchronization Not Supported */
392 if (cb)
393 cb(conn_id, (tGATT_STATUS)0x82, handle, value.size(),
394 value.data(), cb_data);
395 break;
396 }
397
398 if (len < 1) {
399 if (cb)
400 cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
401 value.data(), cb_data);
402 break;
403 }
404 STREAM_TO_UINT8(index, pp);
405 --len;
406 ASSERT_EQ(0u, len);
407
408 auto csis_api = CsisClient::Get();
409 int group_id = bluetooth::groups::kGroupUnknown;
410 if (csis_api != nullptr) {
411 group_id = csis_api->GetGroupId(
412 address, ::bluetooth::le_audio::uuid::kCapServiceUuid);
413 }
414
415 if (group_id != bluetooth::groups::kGroupUnknown) {
416 if (cb)
417 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
418 cb_data);
419 /* Send notification from all grouped devices */
420 auto addresses = csis_api->GetDeviceList(group_id);
421 for (auto& addr : addresses) {
422 auto conn = GetTestConnId(addr);
423 InjectActivePresetNotification(conn, addr, handle, value,
424 index, cb, cb_data);
425 }
426 } else {
427 /* Preset Operation Not Possible */
428 if (cb)
429 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
430 value.data(), cb_data);
431 }
432 } break;
433
434 case ::bluetooth::le_audio::has::PresetCtpOpcode::SET_NEXT_PRESET: {
435 ASSERT_EQ(0u, len);
436 ASSERT_NE(0u, current_peer_active_preset_idx_.count(conn_id));
437 ASSERT_NE(0u, current_peer_presets_.count(conn_id));
438
439 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
440 auto presets = current_peer_presets_.at(conn_id);
441 auto current = presets.find(current_preset);
442 if (current != presets.end()) {
443 ++current;
444 if (current == presets.end()) current = presets.begin();
445
446 current_peer_active_preset_idx_.insert_or_assign(
447 conn_id, current->GetIndex());
448 InjectActivePresetNotification(conn_id, address, handle, value,
449 current->GetIndex(), cb,
450 cb_data);
451
452 } else {
453 /* Preset Operation Not Possible */
454 if (cb)
455 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
456 value.data(), cb_data);
457 }
458 } break;
459
460 case ::bluetooth::le_audio::has::PresetCtpOpcode::SET_PREV_PRESET: {
461 ASSERT_EQ(0u, len);
462 ASSERT_NE(0u, current_peer_active_preset_idx_.count(conn_id));
463 ASSERT_NE(0u, current_peer_presets_.count(conn_id));
464
465 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
466 auto presets = current_peer_presets_.at(conn_id);
467 auto rit = presets.rbegin();
468 while (rit != presets.rend()) {
469 if (rit->GetIndex() == current_preset) {
470 rit++;
471 /* Wrap around */
472 if (rit == presets.rend()) {
473 rit = presets.rbegin();
474 }
475 break;
476 }
477 rit++;
478 }
479
480 if (rit != presets.rend()) {
481 if (cb)
482 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
483 cb_data);
484 current_peer_active_preset_idx_.insert_or_assign(
485 conn_id, rit->GetIndex());
486 InjectActivePresetNotification(conn_id, address, handle, value,
487 rit->GetIndex(), cb, cb_data);
488 } else {
489 /* Preset Operation Not Possible */
490 if (cb)
491 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
492 value.data(), cb_data);
493 }
494 } break;
495
496 case ::bluetooth::le_audio::has::PresetCtpOpcode::
497 SET_NEXT_PRESET_SYNC: {
498 ASSERT_EQ(0u, len);
499 auto features = current_peer_features_val_.at(conn_id);
500 if ((features & ::bluetooth::has::
501 kFeatureBitPresetSynchronizationSupported) ==
502 0) {
503 /* Synchronization Not Supported */
504 if (cb)
505 cb(conn_id, (tGATT_STATUS)0x82, handle, value.size(),
506 value.data(), cb_data);
507 break;
508 }
509
510 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
511 auto presets = current_peer_presets_.at(conn_id);
512 auto rit = presets.begin();
513 while (rit != presets.end()) {
514 if (rit->GetIndex() == current_preset) {
515 rit++;
516 /* Wrap around */
517 if (rit == presets.end()) {
518 rit = presets.begin();
519 }
520 break;
521 }
522 rit++;
523 }
524
525 if (rit != presets.end()) {
526 auto synced_group = mock_csis_client_module_.GetGroupId(
527 GetTestAddress(conn_id),
528 ::bluetooth::le_audio::uuid::kCapServiceUuid);
529 auto addresses =
530 mock_csis_client_module_.GetDeviceList(synced_group);
531
532 // Emulate locally synced op. - notify from all of the devices
533 for (auto addr : addresses) {
534 auto cid = GetTestConnId(addr);
535 if ((cid == conn_id) && (cb != nullptr))
536 cb(cid, GATT_SUCCESS, handle, value.size(), value.data(),
537 cb_data);
538
539 current_peer_active_preset_idx_.insert_or_assign(
540 conn_id, rit->GetIndex());
541 InjectActivePresetNotification(cid, addr, handle, value,
542 rit->GetIndex(), cb, cb_data);
543 }
544 } else {
545 /* Preset Operation Not Possible */
546 if (cb)
547 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
548 value.data(), cb_data);
549 }
550 } break;
551
552 case ::bluetooth::le_audio::has::PresetCtpOpcode::
553 SET_PREV_PRESET_SYNC: {
554 ASSERT_EQ(0u, len);
555 auto features = current_peer_features_val_.at(conn_id);
556 if ((features & ::bluetooth::has::
557 kFeatureBitPresetSynchronizationSupported) ==
558 0) {
559 /* Synchronization Not Supported */
560 if (cb)
561 cb(conn_id, (tGATT_STATUS)0x82, handle, value.size(),
562 value.data(), cb_data);
563 break;
564 }
565
566 auto current_preset = current_peer_active_preset_idx_.at(conn_id);
567 auto presets = current_peer_presets_.at(conn_id);
568 auto rit = presets.rbegin();
569 while (rit != presets.rend()) {
570 if (rit->GetIndex() == current_preset) {
571 rit++;
572 /* Wrap around */
573 if (rit == presets.rend()) {
574 rit = presets.rbegin();
575 }
576 break;
577 }
578 rit++;
579 }
580
581 if (rit != presets.rend()) {
582 auto synced_group = mock_csis_client_module_.GetGroupId(
583 GetTestAddress(conn_id),
584 ::bluetooth::le_audio::uuid::kCapServiceUuid);
585 auto addresses =
586 mock_csis_client_module_.GetDeviceList(synced_group);
587
588 // Emulate locally synced op. - notify from all of the devices
589 for (auto addr : addresses) {
590 auto cid = GetTestConnId(addr);
591 if ((cid == conn_id) && (cb != nullptr))
592 cb(cid, GATT_SUCCESS, handle, value.size(), value.data(),
593 cb_data);
594
595 current_peer_active_preset_idx_.insert_or_assign(
596 conn_id, rit->GetIndex());
597 InjectActivePresetNotification(cid, addr, handle, value,
598 rit->GetIndex(), cb, cb_data);
599 }
600 } else {
601 /* Preset Operation Not Possible */
602 if (cb)
603 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(),
604 value.data(), cb_data);
605 }
606 } break;
607
608 case ::bluetooth::le_audio::has::PresetCtpOpcode::
609 WRITE_PRESET_NAME: {
610 STREAM_TO_UINT8(index, pp);
611 --len;
612 auto name = std::string(pp, pp + len);
613 len = 0;
614
615 ASSERT_NE(0u, current_peer_presets_.count(conn_id));
616 auto presets = current_peer_presets_.at(conn_id);
617 auto rit = presets.rbegin();
618 auto current = rit;
619 while (rit != presets.rend()) {
620 if (rit->GetIndex() == index) {
621 current = rit;
622 rit++;
623 break;
624 }
625 rit++;
626 }
627
628 auto prev_index = (rit == presets.rend()) ? 0 : rit->GetIndex();
629
630 ASSERT_NE(current, presets.rend());
631 if (cb)
632 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
633 cb_data);
634
635 auto new_preset = HasPreset(current->GetIndex(),
636 current->GetProperties(), name);
637 presets.erase(current->GetIndex());
638 presets.insert(new_preset);
639
640 InjectPresetChanged(conn_id, address, indicate, new_preset,
641 prev_index,
642 ::bluetooth::le_audio::has::
643 PresetCtpChangeId::PRESET_GENERIC_UPDATE,
644 true);
645 } break;
646
647 default:
648 if (cb)
649 cb(conn_id, GATT_INVALID_HANDLE, handle, value.size(),
650 value.data(), cb_data);
651 break;
652 }
653 }));
654 }
655
SetUp(void)656 void SetUp(void) override {
657 reset_mock_function_count_map();
658 bluetooth::manager::SetMockBtmInterface(&btm_interface);
659 bluetooth::storage::SetMockBtifStorageInterface(&btif_storage_interface_);
660 gatt::SetMockBtaGattInterface(&gatt_interface);
661 gatt::SetMockBtaGattQueue(&gatt_queue);
662 callbacks.reset(new MockHasCallbacks());
663
664 encryption_result = true;
665
666 ON_CALL(btm_interface, IsLinkKeyKnown(_, _))
667 .WillByDefault(DoAll(Return(true)));
668
669 ON_CALL(btm_interface, SetEncryption(_, _, _, _, _))
670 .WillByDefault(
671 Invoke([this](const RawAddress& bd_addr, tBT_TRANSPORT transport,
672 tBTM_SEC_CALLBACK* p_callback, void* p_ref_data,
673 tBTM_BLE_SEC_ACT sec_act) -> tBTM_STATUS {
674 InjectEncryptionEvent(bd_addr);
675 return BTM_SUCCESS;
676 }));
677
678 MockCsisClient::SetMockInstanceForTesting(&mock_csis_client_module_);
679 ON_CALL(mock_csis_client_module_, Get())
680 .WillByDefault(Return(&mock_csis_client_module_));
681 ON_CALL(mock_csis_client_module_, IsCsisClientRunning())
682 .WillByDefault(Return(true));
683
684 /* default action for GetCharacteristic function call */
685 ON_CALL(gatt_interface, GetCharacteristic(_, _))
686 .WillByDefault(
687 Invoke([&](uint16_t conn_id,
688 uint16_t handle) -> const gatt::Characteristic* {
689 std::list<gatt::Service>& services = services_map[conn_id];
690 for (auto const& service : services) {
691 for (auto const& characteristic : service.characteristics) {
692 if (characteristic.value_handle == handle) {
693 return &characteristic;
694 }
695 }
696 }
697
698 return nullptr;
699 }));
700
701 /* default action for GetOwningService function call */
702 ON_CALL(gatt_interface, GetOwningService(_, _))
703 .WillByDefault(Invoke(
704 [&](uint16_t conn_id, uint16_t handle) -> const gatt::Service* {
705 std::list<gatt::Service>& services = services_map[conn_id];
706 for (auto const& service : services) {
707 if (service.handle <= handle && service.end_handle >= handle) {
708 return &service;
709 }
710 }
711
712 return nullptr;
713 }));
714
715 ON_CALL(gatt_interface, ServiceSearchRequest(_, _))
716 .WillByDefault(WithArg<0>(Invoke(
717 [&](uint16_t conn_id) { InjectSearchCompleteEvent(conn_id); })));
718
719 /* default action for GetServices function call */
720 ON_CALL(gatt_interface, GetServices(_))
721 .WillByDefault(WithArg<0>(
722 Invoke([&](uint16_t conn_id) -> std::list<gatt::Service>* {
723 return &services_map[conn_id];
724 })));
725
726 /* default action for RegisterForNotifications function call */
727 ON_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
728 .WillByDefault(Return(GATT_SUCCESS));
729
730 /* default action for DeregisterForNotifications function call */
731 ON_CALL(gatt_interface, DeregisterForNotifications(gatt_if, _, _))
732 .WillByDefault(Return(GATT_SUCCESS));
733
734 /* default action for WriteDescriptor function call */
735 ON_CALL(gatt_queue, WriteDescriptor(_, _, _, _, _, _))
736 .WillByDefault(
737 Invoke([](uint16_t conn_id, uint16_t handle,
738 std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
739 GATT_WRITE_OP_CB cb, void* cb_data) -> void {
740 if (cb)
741 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
742 cb_data);
743 }));
744
745 /* by default connect only direct connection requests */
746 ON_CALL(gatt_interface, Open(_, _, _, _))
747 .WillByDefault(
748 Invoke([&](tGATT_IF client_if, const RawAddress& remote_bda,
749 tBTM_BLE_CONN_TYPE connection_type, bool opportunistic) {
750 if (connection_type == BTM_BLE_DIRECT_CONNECTION)
751 InjectConnectedEvent(remote_bda, GetTestConnId(remote_bda));
752 }));
753
754 ON_CALL(gatt_interface, Close(_))
755 .WillByDefault(Invoke(
756 [&](uint16_t conn_id) { InjectDisconnectedEvent(conn_id); }));
757 }
758
TearDown(void)759 void TearDown(void) override {
760 services_map.clear();
761 gatt::SetMockBtaGattQueue(nullptr);
762 gatt::SetMockBtaGattInterface(nullptr);
763 bluetooth::storage::SetMockBtifStorageInterface(nullptr);
764 bluetooth::manager::SetMockBtmInterface(nullptr);
765 callbacks.reset();
766
767 current_peer_active_preset_idx_.clear();
768 current_peer_features_val_.clear();
769 }
770
TestAppRegister(void)771 void TestAppRegister(void) {
772 BtaAppRegisterCallback app_register_callback;
773 EXPECT_CALL(gatt_interface, AppRegister(_, _, _))
774 .WillOnce(DoAll(SaveArg<0>(&gatt_callback),
775 SaveArg<1>(&app_register_callback)));
776 HasClient::Initialize(callbacks.get(), base::DoNothing());
777 ASSERT_TRUE(gatt_callback);
778 ASSERT_TRUE(app_register_callback);
779 app_register_callback.Run(gatt_if, GATT_SUCCESS);
780 ASSERT_TRUE(HasClient::IsHasClientRunning());
781 Mock::VerifyAndClearExpectations(&gatt_interface);
782 }
783
TestAppUnregister(void)784 void TestAppUnregister(void) {
785 EXPECT_CALL(gatt_interface, AppDeregister(gatt_if));
786 HasClient::CleanUp();
787 ASSERT_FALSE(HasClient::IsHasClientRunning());
788 gatt_callback = nullptr;
789 }
790
TestConnect(const RawAddress & address)791 void TestConnect(const RawAddress& address) {
792 ON_CALL(btm_interface, BTM_IsEncrypted(address, _))
793 .WillByDefault(DoAll(Return(encryption_result)));
794
795 EXPECT_CALL(gatt_interface,
796 Open(gatt_if, address, BTM_BLE_DIRECT_CONNECTION, _));
797 HasClient::Get()->Connect(address);
798
799 Mock::VerifyAndClearExpectations(&*callbacks);
800 Mock::VerifyAndClearExpectations(&gatt_queue);
801 Mock::VerifyAndClearExpectations(&gatt_interface);
802 Mock::VerifyAndClearExpectations(&btm_interface);
803 }
804
TestDisconnect(const RawAddress & address,uint16_t conn_id)805 void TestDisconnect(const RawAddress& address, uint16_t conn_id) {
806 EXPECT_CALL(gatt_interface, CancelOpen(_, address, _)).Times(AnyNumber());
807 if (conn_id != GATT_INVALID_CONN_ID) {
808 assert(0);
809 EXPECT_CALL(gatt_interface, Close(conn_id));
810 } else {
811 EXPECT_CALL(gatt_interface, CancelOpen(gatt_if, address, _));
812 }
813 HasClient::Get()->Disconnect(address);
814 }
815
TestAddFromStorage(const RawAddress & address,uint8_t features,bool auto_connect)816 void TestAddFromStorage(const RawAddress& address, uint8_t features,
817 bool auto_connect) {
818 if (auto_connect) {
819 EXPECT_CALL(gatt_interface,
820 Open(gatt_if, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, _));
821 HasClient::Get()->AddFromStorage(address, features, auto_connect);
822
823 /* Inject connected event for autoconnect/background connection */
824 InjectConnectedEvent(address, GetTestConnId(address));
825 } else {
826 EXPECT_CALL(gatt_interface, Open(gatt_if, address, _, _)).Times(0);
827 HasClient::Get()->AddFromStorage(address, features, auto_connect);
828 }
829
830 Mock::VerifyAndClearExpectations(&gatt_interface);
831 }
832
InjectConnectedEvent(const RawAddress & address,uint16_t conn_id,tGATT_STATUS status=GATT_SUCCESS)833 void InjectConnectedEvent(const RawAddress& address, uint16_t conn_id,
834 tGATT_STATUS status = GATT_SUCCESS) {
835 tBTA_GATTC_OPEN event_data = {
836 .status = status,
837 .conn_id = conn_id,
838 .client_if = gatt_if,
839 .remote_bda = address,
840 .transport = GATT_TRANSPORT_LE,
841 .mtu = 240,
842 };
843
844 connected_devices[conn_id] = address;
845 gatt_callback(BTA_GATTC_OPEN_EVT, (tBTA_GATTC*)&event_data);
846 }
847
InjectDisconnectedEvent(uint16_t conn_id,tGATT_DISCONN_REASON reason=GATT_CONN_TERMINATE_LOCAL_HOST,bool allow_fake_conn=false)848 void InjectDisconnectedEvent(
849 uint16_t conn_id,
850 tGATT_DISCONN_REASON reason = GATT_CONN_TERMINATE_LOCAL_HOST,
851 bool allow_fake_conn = false) {
852 if (!allow_fake_conn) ASSERT_NE(connected_devices.count(conn_id), 0u);
853
854 tBTA_GATTC_CLOSE event_data = {
855 .conn_id = conn_id,
856 .status = GATT_SUCCESS,
857 .client_if = gatt_if,
858 .remote_bda = connected_devices[conn_id],
859 .reason = reason,
860 };
861
862 connected_devices.erase(conn_id);
863 gatt_callback(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&event_data);
864 }
865
InjectSearchCompleteEvent(uint16_t conn_id)866 void InjectSearchCompleteEvent(uint16_t conn_id) {
867 tBTA_GATTC_SEARCH_CMPL event_data = {
868 .conn_id = conn_id,
869 .status = GATT_SUCCESS,
870 };
871
872 gatt_callback(BTA_GATTC_SEARCH_CMPL_EVT, (tBTA_GATTC*)&event_data);
873 }
874
InjectNotificationEvent(const RawAddress & test_address,uint16_t conn_id,uint16_t handle,std::vector<uint8_t> value,bool indicate=false)875 void InjectNotificationEvent(const RawAddress& test_address, uint16_t conn_id,
876 uint16_t handle, std::vector<uint8_t> value,
877 bool indicate = false) {
878 tBTA_GATTC_NOTIFY event_data = {
879 .conn_id = conn_id,
880 .bda = test_address,
881 .handle = handle,
882 .len = (uint8_t)value.size(),
883 .is_notify = !indicate,
884 };
885
886 ASSERT_TRUE(value.size() < GATT_MAX_ATTR_LEN);
887 std::copy(value.begin(), value.end(), event_data.value);
888 gatt_callback(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC*)&event_data);
889 }
890
InjectEncryptionEvent(const RawAddress & test_address)891 void InjectEncryptionEvent(const RawAddress& test_address) {
892 tBTA_GATTC_ENC_CMPL_CB event_data = {
893 .client_if = static_cast<tGATT_IF>(GetTestConnId(test_address)),
894 .remote_bda = test_address,
895 };
896
897 gatt_callback(BTA_GATTC_ENC_CMPL_CB_EVT, (tBTA_GATTC*)&event_data);
898 }
899
SetEncryptionResult(const RawAddress & address,bool success)900 void SetEncryptionResult(const RawAddress& address, bool success) {
901 encryption_result = success;
902
903 ON_CALL(btm_interface, BTM_IsEncrypted(address, _))
904 .WillByDefault(DoAll(Return(encryption_result)));
905
906 ON_CALL(btm_interface, IsLinkKeyKnown(address, _))
907 .WillByDefault(DoAll(Return(true)));
908 }
909
InjectNotifyReadPresetResponse(uint16_t conn_id,RawAddress const & address,uint16_t handle,const HasPreset & preset,bool indicate,bool is_last)910 void InjectNotifyReadPresetResponse(uint16_t conn_id,
911 RawAddress const& address,
912 uint16_t handle, const HasPreset& preset,
913 bool indicate, bool is_last) {
914 std::vector<uint8_t> value;
915
916 value.push_back(static_cast<std::underlying_type_t<
917 ::bluetooth::le_audio::has::PresetCtpOpcode>>(
918 ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESET_RESPONSE));
919 value.push_back(is_last ? 0x01 : 0x00);
920
921 preset.ToCharacteristicValue(value);
922 InjectNotificationEvent(address, conn_id, handle, value, indicate);
923 }
924
InjectPresetChanged(uint16_t conn_id,RawAddress const & address,bool indicate,const HasPreset & preset,uint8_t prev_index,::bluetooth::le_audio::has::PresetCtpChangeId change_id,bool is_last)925 void InjectPresetChanged(
926 uint16_t conn_id, RawAddress const& address, bool indicate,
927 const HasPreset& preset, uint8_t prev_index,
928 ::bluetooth::le_audio::has::PresetCtpChangeId change_id, bool is_last) {
929 std::vector<uint8_t> value;
930
931 value.push_back(static_cast<std::underlying_type_t<
932 ::bluetooth::le_audio::has::PresetCtpOpcode>>(
933 ::bluetooth::le_audio::has::PresetCtpOpcode::PRESET_CHANGED));
934 value.push_back(static_cast<uint8_t>(change_id));
935 value.push_back(is_last ? 0x01 : 0x00);
936
937 switch (change_id) {
938 case ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE:
939 value.push_back(prev_index);
940 preset.ToCharacteristicValue(value);
941 break;
942 case ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_DELETED:
943 case ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_AVAILABLE:
944 case ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_UNAVAILABLE:
945 default:
946 value.push_back(preset.GetIndex());
947 break;
948 }
949
950 InjectNotificationEvent(address, conn_id, HasDbBuilder::kPresetsCtpValHdl,
951 value, indicate);
952 }
953
InjectNotifyReadPresetsResponse(uint16_t conn_id,RawAddress const & address,uint16_t handle,std::vector<uint8_t> value,bool indicate,int index,int num_of_indices,GATT_WRITE_OP_CB cb,void * cb_data)954 void InjectNotifyReadPresetsResponse(
955 uint16_t conn_id, RawAddress const& address, uint16_t handle,
956 std::vector<uint8_t> value, bool indicate, int index, int num_of_indices,
957 GATT_WRITE_OP_CB cb, void* cb_data) {
958 auto presets = current_peer_presets_.at(conn_id);
959 log::assert_that(!presets.empty(), "Mocking error!");
960
961 /* Index is a start index, not necessary is a valid index for the
962 * peer device */
963 auto preset = presets.find(index);
964 while (preset == presets.end() &&
965 index++ <= ::bluetooth::le_audio::has::kMaxNumOfPresets) {
966 preset = presets.find(index);
967 }
968
969 if (preset == presets.end()) {
970 /* operation not possible */
971 if (cb)
972 cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(), value.data(),
973 cb_data);
974
975 return;
976 }
977
978 if (cb)
979 cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data);
980 /* Notify presets */
981 int num_of_notif = 1;
982 while (1) {
983 bool last =
984 preset == std::prev(presets.end()) || num_of_notif == num_of_indices;
985 InjectNotifyReadPresetResponse(conn_id, address, handle, *preset,
986 indicate, (last));
987 if (last) return;
988
989 num_of_notif++;
990 preset++;
991 }
992 }
993
InjectActivePresetNotification(uint16_t conn_id,RawAddress const & address,uint16_t handle,std::vector<uint8_t> wr_value,uint8_t index,GATT_WRITE_OP_CB cb,void * cb_data)994 void InjectActivePresetNotification(uint16_t conn_id,
995 RawAddress const& address,
996 uint16_t handle,
997 std::vector<uint8_t> wr_value,
998 uint8_t index, GATT_WRITE_OP_CB cb,
999 void* cb_data) {
1000 auto presets = current_peer_presets_.at(conn_id);
1001 log::assert_that(!presets.empty(), "Mocking error!");
1002
1003 auto preset = presets.find(index);
1004 if (preset == presets.end()) {
1005 /* preset operation not possible */
1006 if (cb)
1007 cb(conn_id, (tGATT_STATUS)0x83, handle, wr_value.size(),
1008 wr_value.data(), cb_data);
1009 return;
1010 }
1011
1012 std::vector<uint8_t> value;
1013 value.push_back(index);
1014 InjectNotificationEvent(
1015 address, conn_id, HasDbBuilder::kActivePresetIndexValHdl, value, false);
1016 }
1017
SetSampleDatabaseHasNoFeatures(const RawAddress & address)1018 void SetSampleDatabaseHasNoFeatures(const RawAddress& address) {
1019 HasDbBuilder builder = {
1020 .has = true,
1021 .features = false,
1022 .features_ntf = false,
1023 .preset_cp = true,
1024 .preset_cp_ntf = false,
1025 .preset_cp_ind = true,
1026 .active_preset_idx = true,
1027 .active_preset_idx_ntf = true,
1028 };
1029 set_sample_database(address, builder);
1030 }
1031
SetSampleDatabaseHasNoPresetChange(const RawAddress & address,uint8_t features_value=0x00)1032 void SetSampleDatabaseHasNoPresetChange(const RawAddress& address,
1033 uint8_t features_value = 0x00) {
1034 HasDbBuilder builder = {
1035 .has = true,
1036 .features = true,
1037 .features_ntf = false,
1038 .preset_cp = false,
1039 .preset_cp_ntf = false,
1040 .preset_cp_ind = false,
1041 .active_preset_idx = false,
1042 .active_preset_idx_ntf = false,
1043 };
1044 set_sample_database(address, builder, features_value);
1045 }
1046
SetSampleDatabaseHasNoOptionalNtf(const RawAddress & address,uint8_t features=0x00)1047 void SetSampleDatabaseHasNoOptionalNtf(const RawAddress& address,
1048 uint8_t features = 0x00) {
1049 HasDbBuilder builder = {
1050 .has = true,
1051 .features = true,
1052 .features_ntf = false,
1053 .preset_cp = true,
1054 .preset_cp_ntf = false,
1055 .preset_cp_ind = true,
1056 .active_preset_idx = true,
1057 .active_preset_idx_ntf = true,
1058 };
1059 set_sample_database(address, builder, features);
1060 }
1061
SetSampleDatabaseNoHas(const RawAddress & address,uint8_t features=0x00)1062 void SetSampleDatabaseNoHas(const RawAddress& address,
1063 uint8_t features = 0x00) {
1064 HasDbBuilder builder = {
1065 .has = false,
1066 .features = false,
1067 .features_ntf = false,
1068 .preset_cp = false,
1069 .preset_cp_ntf = false,
1070 .preset_cp_ind = false,
1071 .active_preset_idx = true,
1072 .active_preset_idx_ntf = true,
1073 };
1074 set_sample_database(address, builder, features);
1075 }
1076
SetSampleDatabaseHasBrokenNoActivePreset(const RawAddress & address,uint8_t features=0x00)1077 void SetSampleDatabaseHasBrokenNoActivePreset(const RawAddress& address,
1078 uint8_t features = 0x00) {
1079 HasDbBuilder builder = {
1080 .has = true,
1081 .features = true,
1082 .features_ntf = false,
1083 .preset_cp = true,
1084 .preset_cp_ntf = true,
1085 .preset_cp_ind = true,
1086 .active_preset_idx = false,
1087 .active_preset_idx_ntf = false,
1088 };
1089 set_sample_database(address, builder, features);
1090 }
1091
SetSampleDatabaseHasBrokenNoActivePresetNtf(const RawAddress & address,uint8_t features=0x00)1092 void SetSampleDatabaseHasBrokenNoActivePresetNtf(const RawAddress& address,
1093 uint8_t features = 0x00) {
1094 HasDbBuilder builder = {
1095 .has = true,
1096 .features = true,
1097 .features_ntf = false,
1098 .preset_cp = true,
1099 .preset_cp_ntf = true,
1100 .preset_cp_ind = true,
1101 .active_preset_idx = true,
1102 .active_preset_idx_ntf = false,
1103 };
1104 set_sample_database(address, builder, features);
1105 }
1106
SetSampleDatabaseHasOnlyFeaturesNtf(const RawAddress & address,uint8_t features=0x00)1107 void SetSampleDatabaseHasOnlyFeaturesNtf(const RawAddress& address,
1108 uint8_t features = 0x00) {
1109 HasDbBuilder builder = {
1110 .has = true,
1111 .features = true,
1112 .features_ntf = true,
1113 .preset_cp = false,
1114 .preset_cp_ntf = false,
1115 .preset_cp_ind = false,
1116 .active_preset_idx = false,
1117 .active_preset_idx_ntf = false,
1118 };
1119 set_sample_database(address, builder, features);
1120 }
1121
SetSampleDatabaseHasOnlyFeaturesNoNtf(const RawAddress & address,uint8_t features=0x00)1122 void SetSampleDatabaseHasOnlyFeaturesNoNtf(const RawAddress& address,
1123 uint8_t features = 0x00) {
1124 HasDbBuilder builder = {
1125 .has = true,
1126 .features = true,
1127 .features_ntf = false,
1128 .preset_cp = false,
1129 .preset_cp_ntf = false,
1130 .preset_cp_ind = false,
1131 .active_preset_idx = false,
1132 .active_preset_idx_ntf = false,
1133 };
1134 set_sample_database(address, builder, features);
1135 }
1136
SetSampleDatabaseHasPresetsNtf(const RawAddress & address,uint8_t features=bluetooth::has::kFeatureBitHearingAidTypeMonaural,std::optional<std::set<HasPreset,HasPreset::ComparatorDesc>> presets=std::nullopt)1137 void SetSampleDatabaseHasPresetsNtf(
1138 const RawAddress& address,
1139 uint8_t features = bluetooth::has::kFeatureBitHearingAidTypeMonaural,
1140 std::optional<std::set<HasPreset, HasPreset::ComparatorDesc>> presets =
1141 std::nullopt) {
1142 HasDbBuilder builder = {
1143 .has = true,
1144 .features = true,
1145 .features_ntf = true,
1146 .preset_cp = true,
1147 .preset_cp_ntf = true,
1148 .preset_cp_ind = true,
1149 .active_preset_idx = true,
1150 .active_preset_idx_ntf = true,
1151 };
1152
1153 set_sample_database(address, builder, features, presets);
1154 }
1155
SetSampleDatabaseHasNoPresetsFlagsOnly(const RawAddress & address)1156 void SetSampleDatabaseHasNoPresetsFlagsOnly(const RawAddress& address) {
1157 uint8_t features = bluetooth::has::kFeatureBitHearingAidTypeMonaural;
1158 HasDbBuilder builder = {
1159 .has = true,
1160 .features = true,
1161 .features_ntf = true,
1162 .preset_cp = false,
1163 .preset_cp_ntf = false,
1164 .preset_cp_ind = false,
1165 .active_preset_idx = false,
1166 .active_preset_idx_ntf = false,
1167 };
1168
1169 set_sample_database(address, builder, features, std::nullopt);
1170 }
1171
1172 std::unique_ptr<MockHasCallbacks> callbacks;
1173 bluetooth::manager::MockBtmInterface btm_interface;
1174 bluetooth::storage::MockBtifStorageInterface btif_storage_interface_;
1175 gatt::MockBtaGattInterface gatt_interface;
1176 gatt::MockBtaGattQueue gatt_queue;
1177 MockCsisClient mock_csis_client_module_;
1178 tBTA_GATTC_CBACK* gatt_callback;
1179 const uint8_t gatt_if = 0xfe;
1180 std::map<uint8_t, RawAddress> connected_devices;
1181 std::map<uint16_t, std::list<gatt::Service>> services_map;
1182 bool encryption_result;
1183 };
1184
1185 class HasClientTest : public HasClientTestBase {
SetUp(void)1186 void SetUp(void) override {
1187 HasClientTestBase::SetUp();
1188 TestAppRegister();
1189 }
TearDown(void)1190 void TearDown(void) override {
1191 TestAppUnregister();
1192 HasClientTestBase::TearDown();
1193 }
1194 };
1195
TEST_F(HasClientTestBase,test_get_uninitialized)1196 TEST_F(HasClientTestBase, test_get_uninitialized) {
1197 ASSERT_DEATH(HasClient::Get(), "");
1198 }
1199
TEST_F(HasClientTestBase,test_initialize)1200 TEST_F(HasClientTestBase, test_initialize) {
1201 HasClient::Initialize(callbacks.get(), base::DoNothing());
1202 ASSERT_TRUE(HasClient::IsHasClientRunning());
1203 HasClient::CleanUp();
1204 }
1205
TEST_F(HasClientTestBase,test_initialize_twice)1206 TEST_F(HasClientTestBase, test_initialize_twice) {
1207 HasClient::Initialize(callbacks.get(), base::DoNothing());
1208 HasClient* has_p = HasClient::Get();
1209 HasClient::Initialize(callbacks.get(), base::DoNothing());
1210 ASSERT_EQ(has_p, HasClient::Get());
1211 HasClient::CleanUp();
1212 }
1213
TEST_F(HasClientTestBase,test_cleanup_initialized)1214 TEST_F(HasClientTestBase, test_cleanup_initialized) {
1215 HasClient::Initialize(callbacks.get(), base::DoNothing());
1216 HasClient::CleanUp();
1217 ASSERT_FALSE(HasClient::IsHasClientRunning());
1218 }
1219
TEST_F(HasClientTestBase,test_cleanup_uninitialized)1220 TEST_F(HasClientTestBase, test_cleanup_uninitialized) {
1221 HasClient::CleanUp();
1222 ASSERT_FALSE(HasClient::IsHasClientRunning());
1223 }
1224
TEST_F(HasClientTestBase,test_app_registration)1225 TEST_F(HasClientTestBase, test_app_registration) {
1226 TestAppRegister();
1227 TestAppUnregister();
1228 }
1229
TEST_F(HasClientTest,test_connect)1230 TEST_F(HasClientTest, test_connect) { TestConnect(GetTestAddress(1)); }
1231
TEST_F(HasClientTest,test_add_from_storage)1232 TEST_F(HasClientTest, test_add_from_storage) {
1233 TestAddFromStorage(GetTestAddress(1), 0, true);
1234 TestAddFromStorage(GetTestAddress(2), 0, false);
1235 }
1236
TEST_F(HasClientTest,test_connect_after_remove)1237 TEST_F(HasClientTest, test_connect_after_remove) {
1238 const RawAddress test_address = GetTestAddress(1);
1239
1240 /* Override the default action to prevent us sendind the connected event */
1241 EXPECT_CALL(gatt_interface,
1242 Open(gatt_if, test_address, BTM_BLE_DIRECT_CONNECTION, _))
1243 .WillOnce(Return());
1244 HasClient::Get()->Connect(test_address);
1245 TestDisconnect(test_address, GATT_INVALID_CONN_ID);
1246 Mock::VerifyAndClearExpectations(&gatt_interface);
1247
1248 EXPECT_CALL(*callbacks,
1249 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1250
1251 // Device has no Link Key
1252 ON_CALL(btm_interface, IsLinkKeyKnown(test_address, _))
1253 .WillByDefault(DoAll(Return(true)));
1254 HasClient::Get()->Connect(test_address);
1255 Mock::VerifyAndClearExpectations(&callbacks);
1256 }
1257
TEST_F(HasClientTest,test_disconnect_non_connected)1258 TEST_F(HasClientTest, test_disconnect_non_connected) {
1259 const RawAddress test_address = GetTestAddress(1);
1260
1261 /* Override the default action to prevent us sendind the connected event */
1262 EXPECT_CALL(gatt_interface,
1263 Open(gatt_if, test_address, BTM_BLE_DIRECT_CONNECTION, _))
1264 .WillOnce(Return());
1265 HasClient::Get()->Connect(test_address);
1266 TestDisconnect(test_address, GATT_INVALID_CONN_ID);
1267 }
1268
TEST_F(HasClientTest,test_has_connected)1269 TEST_F(HasClientTest, test_has_connected) {
1270 const RawAddress test_address = GetTestAddress(1);
1271 /* Minimal possible HA device (only feature flags) */
1272 SetSampleDatabaseHasNoPresetChange(
1273 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1274
1275 EXPECT_CALL(
1276 *callbacks,
1277 OnDeviceAvailable(test_address,
1278 bluetooth::has::kFeatureBitHearingAidTypeBinaural));
1279 EXPECT_CALL(*callbacks,
1280 OnConnectionState(ConnectionState::CONNECTED, test_address));
1281 TestConnect(test_address);
1282 }
1283
TEST_F(HasClientTest,test_disconnect_connected)1284 TEST_F(HasClientTest, test_disconnect_connected) {
1285 const RawAddress test_address = GetTestAddress(1);
1286 /* Minimal possible HA device (only feature flags) */
1287 SetSampleDatabaseHasNoPresetChange(
1288 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1289
1290 EXPECT_CALL(*callbacks,
1291 OnConnectionState(ConnectionState::CONNECTED, test_address))
1292 .Times(1);
1293 TestConnect(test_address);
1294
1295 EXPECT_CALL(*callbacks,
1296 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1297 .Times(1);
1298 TestDisconnect(test_address, 1);
1299 }
1300
TEST_F(HasClientTest,test_disconnected_while_autoconnect)1301 TEST_F(HasClientTest, test_disconnected_while_autoconnect) {
1302 const RawAddress test_address = GetTestAddress(1);
1303 TestAddFromStorage(test_address,
1304 bluetooth::has::kFeatureBitHearingAidTypeBinaural, true);
1305 /* autoconnect - don't indicate disconnection */
1306 EXPECT_CALL(*callbacks,
1307 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1308 .Times(0);
1309 /* Verify that the device still can connect in te background */
1310 InjectDisconnectedEvent(1, GATT_CONN_TERMINATE_PEER_USER, true);
1311 }
1312
TEST_F(HasClientTest,test_encryption_failed)1313 TEST_F(HasClientTest, test_encryption_failed) {
1314 const RawAddress test_address = GetTestAddress(1);
1315 SetSampleDatabaseHasNoPresetChange(
1316 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1317 EXPECT_CALL(*callbacks,
1318 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1319 .Times(1);
1320 EXPECT_CALL(*callbacks,
1321 OnConnectionState(ConnectionState::CONNECTED, test_address))
1322 .Times(0);
1323 SetEncryptionResult(test_address, false);
1324 TestConnect(test_address);
1325 }
1326
TEST_F(HasClientTest,test_service_discovery_complete_before_encryption)1327 TEST_F(HasClientTest, test_service_discovery_complete_before_encryption) {
1328 const RawAddress test_address = GetTestAddress(1);
1329 SetSampleDatabaseHasPresetsNtf(
1330 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1331
1332 EXPECT_CALL(*callbacks,
1333 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1334 .Times(0);
1335 EXPECT_CALL(*callbacks,
1336 OnConnectionState(ConnectionState::CONNECTED, test_address))
1337 .Times(0);
1338
1339 SetEncryptionResult(test_address, false);
1340 ON_CALL(btm_interface, SetEncryption(_, _, _, _, _))
1341 .WillByDefault(Return(BTM_SUCCESS));
1342
1343 TestConnect(test_address);
1344 auto test_conn_id = GetTestConnId(test_address);
1345 InjectSearchCompleteEvent(test_conn_id);
1346
1347 Mock::VerifyAndClearExpectations(callbacks.get());
1348
1349 EXPECT_CALL(*callbacks,
1350 OnConnectionState(ConnectionState::CONNECTED, test_address))
1351 .Times(1);
1352
1353 SetEncryptionResult(test_address, true);
1354 InjectEncryptionEvent(test_address);
1355 Mock::VerifyAndClearExpectations(callbacks.get());
1356 }
1357
TEST_F(HasClientTest,test_disconnect_when_link_key_is_gone)1358 TEST_F(HasClientTest, test_disconnect_when_link_key_is_gone) {
1359 const RawAddress test_address = GetTestAddress(1);
1360 SetSampleDatabaseHasPresetsNtf(
1361 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1362
1363 EXPECT_CALL(*callbacks,
1364 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1365 .Times(0);
1366 EXPECT_CALL(*callbacks,
1367 OnConnectionState(ConnectionState::CONNECTED, test_address))
1368 .Times(0);
1369
1370 ON_CALL(btm_interface, BTM_IsEncrypted(test_address, _))
1371 .WillByDefault(DoAll(Return(false)));
1372 ON_CALL(btm_interface, SetEncryption(test_address, _, _, _, _))
1373 .WillByDefault(Return(BTM_ERR_KEY_MISSING));
1374
1375 auto test_conn_id = GetTestConnId(test_address);
1376 EXPECT_CALL(gatt_interface, Close(test_conn_id)).Times(1);
1377 InjectConnectedEvent(test_address, GetTestConnId(test_address));
1378
1379 Mock::VerifyAndClearExpectations(callbacks.get());
1380 }
1381
TEST_F(HasClientTest,test_reconnect_after_encryption_failed)1382 TEST_F(HasClientTest, test_reconnect_after_encryption_failed) {
1383 const RawAddress test_address = GetTestAddress(1);
1384 SetSampleDatabaseHasNoPresetChange(
1385 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1386 EXPECT_CALL(*callbacks,
1387 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1388 .Times(1);
1389 EXPECT_CALL(*callbacks,
1390 OnConnectionState(ConnectionState::CONNECTED, test_address))
1391 .Times(0);
1392 SetEncryptionResult(test_address, false);
1393 TestConnect(test_address);
1394
1395 EXPECT_CALL(*callbacks,
1396 OnConnectionState(ConnectionState::CONNECTED, test_address))
1397 .Times(1);
1398 SetEncryptionResult(test_address, true);
1399 InjectConnectedEvent(test_address, GetTestConnId(test_address));
1400 }
1401
TEST_F(HasClientTest,test_reconnect_after_encryption_failed_from_storage)1402 TEST_F(HasClientTest, test_reconnect_after_encryption_failed_from_storage) {
1403 const RawAddress test_address = GetTestAddress(1);
1404
1405 SetSampleDatabaseHasNoPresetChange(
1406 test_address, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
1407 SetEncryptionResult(test_address, false);
1408 TestAddFromStorage(test_address, 0, true);
1409 /* autoconnect - don't indicate disconnection */
1410 EXPECT_CALL(*callbacks,
1411 OnConnectionState(ConnectionState::DISCONNECTED, test_address))
1412 .Times(0);
1413 Mock::VerifyAndClearExpectations(&btm_interface);
1414
1415 /* Fake no persistent storage data */
1416 ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(_, _, _))
1417 .WillByDefault([]() { return false; });
1418
1419 EXPECT_CALL(*callbacks,
1420 OnConnectionState(ConnectionState::CONNECTED, test_address))
1421 .Times(1);
1422 SetEncryptionResult(test_address, true);
1423 InjectConnectedEvent(test_address, GetTestConnId(test_address));
1424 }
1425
TEST_F(HasClientTest,test_load_from_storage_and_connect)1426 TEST_F(HasClientTest, test_load_from_storage_and_connect) {
1427 const RawAddress test_address = GetTestAddress(1);
1428 SetSampleDatabaseHasPresetsNtf(test_address, kFeatureBitDynamicPresets);
1429 SetEncryptionResult(test_address, true);
1430
1431 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
1432 HasPreset(5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1433 "YourWritablePreset5"),
1434 HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
1435 }};
1436
1437 /* Load persistent storage data */
1438 ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(test_address, _, _))
1439 .WillByDefault([&has_presets](const RawAddress& address,
1440 std::vector<uint8_t>& presets_bin,
1441 uint8_t& active_preset) {
1442 /* Generate presets binary to be used instead the attribute values */
1443 HasDevice device(address, 0);
1444 device.has_presets = has_presets;
1445 active_preset = 55;
1446
1447 if (device.SerializePresets(presets_bin)) return true;
1448
1449 return false;
1450 });
1451
1452 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1453 .Times(1 // preset control point
1454 + 1 // active preset
1455 + 1); // features
1456
1457 EXPECT_CALL(*callbacks,
1458 OnDeviceAvailable(test_address,
1459 (kFeatureBitWritablePresets |
1460 kFeatureBitPresetSynchronizationSupported |
1461 kFeatureBitHearingAidTypeBanded)));
1462
1463 std::vector<PresetInfo> loaded_preset_details;
1464 EXPECT_CALL(*callbacks,
1465 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1466 PresetInfoReason::ALL_PRESET_INFO, _))
1467 .WillOnce(SaveArg<2>(&loaded_preset_details));
1468
1469 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1470 std::variant<RawAddress, int>(test_address), 55));
1471
1472 EXPECT_CALL(*callbacks,
1473 OnConnectionState(ConnectionState::CONNECTED, test_address));
1474
1475 /* Expect no read or write operations when loading from storage */
1476 EXPECT_CALL(gatt_queue, ReadCharacteristic(1, _, _, _)).Times(0);
1477 EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(3);
1478
1479 TestAddFromStorage(test_address,
1480 kFeatureBitWritablePresets |
1481 kFeatureBitPresetSynchronizationSupported |
1482 kFeatureBitHearingAidTypeBanded,
1483 true);
1484
1485 for (auto const& info : loaded_preset_details) {
1486 auto preset = has_presets.find(info.preset_index);
1487 ASSERT_NE(preset, has_presets.end());
1488 if (preset->GetProperties() & HasPreset::kPropertyAvailable)
1489 ASSERT_TRUE(info.available);
1490 if (preset->GetProperties() & HasPreset::kPropertyWritable)
1491 ASSERT_TRUE(info.writable);
1492 ASSERT_EQ(preset->GetName(), info.preset_name);
1493 }
1494 }
1495
TEST_F(HasClientTest,test_load_from_storage)1496 TEST_F(HasClientTest, test_load_from_storage) {
1497 const RawAddress test_address = GetTestAddress(1);
1498 SetSampleDatabaseHasPresetsNtf(test_address, kFeatureBitDynamicPresets);
1499 SetEncryptionResult(test_address, true);
1500
1501 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
1502 HasPreset(5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1503 "YourWritablePreset5"),
1504 HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
1505 }};
1506
1507 /* Load persistent storage data */
1508 ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(test_address, _, _))
1509 .WillByDefault([&has_presets](const RawAddress& address,
1510 std::vector<uint8_t>& presets_bin,
1511 uint8_t& active_preset) {
1512 /* Generate presets binary to be used instead the attribute values */
1513 HasDevice device(address, 0);
1514 device.has_presets = has_presets;
1515 active_preset = 55;
1516
1517 if (device.SerializePresets(presets_bin)) return true;
1518
1519 return false;
1520 });
1521
1522 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1523 .Times(0); // features
1524
1525 EXPECT_CALL(*callbacks,
1526 OnDeviceAvailable(test_address,
1527 (kFeatureBitWritablePresets |
1528 kFeatureBitPresetSynchronizationSupported |
1529 kFeatureBitHearingAidTypeBanded)));
1530
1531 std::vector<PresetInfo> loaded_preset_details;
1532 EXPECT_CALL(*callbacks,
1533 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1534 PresetInfoReason::ALL_PRESET_INFO, _))
1535 .Times(0);
1536
1537 /* Expect no read or write operations when loading from storage */
1538 EXPECT_CALL(gatt_queue, ReadCharacteristic(1, _, _, _)).Times(0);
1539 EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(0);
1540
1541 TestAddFromStorage(test_address,
1542 kFeatureBitWritablePresets |
1543 kFeatureBitPresetSynchronizationSupported |
1544 kFeatureBitHearingAidTypeBanded,
1545 false);
1546 }
1547
TEST_F(HasClientTest,test_write_to_storage)1548 TEST_F(HasClientTest, test_write_to_storage) {
1549 const RawAddress test_address = GetTestAddress(1);
1550
1551 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
1552 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
1553 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1554 "Preset2"),
1555 }};
1556 SetSampleDatabaseHasPresetsNtf(
1557 test_address,
1558 bluetooth::has::kFeatureBitHearingAidTypeBanded |
1559 bluetooth::has::kFeatureBitWritablePresets |
1560 bluetooth::has::kFeatureBitDynamicPresets,
1561 has_presets);
1562
1563 std::vector<uint8_t> serialized;
1564 EXPECT_CALL(
1565 btif_storage_interface_,
1566 AddLeaudioHasDevice(test_address, _,
1567 bluetooth::has::kFeatureBitHearingAidTypeBanded |
1568 bluetooth::has::kFeatureBitWritablePresets |
1569 bluetooth::has::kFeatureBitDynamicPresets,
1570 1))
1571 .WillOnce(SaveArg<1>(&serialized));
1572 TestConnect(test_address);
1573
1574 /* Deserialize the written binary to verify the content */
1575 HasDevice clone(test_address,
1576 bluetooth::has::kFeatureBitHearingAidTypeBanded |
1577 bluetooth::has::kFeatureBitWritablePresets |
1578 bluetooth::has::kFeatureBitDynamicPresets);
1579 ASSERT_TRUE(HasDevice::DeserializePresets(serialized.data(),
1580 serialized.size(), clone));
1581 auto storage_info = clone.GetAllPresetInfo();
1582 ASSERT_EQ(storage_info.size(), has_presets.size());
1583 for (auto const& info : storage_info) {
1584 auto preset = has_presets.find(info.preset_index);
1585 ASSERT_NE(preset, has_presets.end());
1586 if (preset->GetProperties() & HasPreset::kPropertyAvailable)
1587 ASSERT_TRUE(info.available);
1588 if (preset->GetProperties() & HasPreset::kPropertyWritable)
1589 ASSERT_TRUE(info.writable);
1590 ASSERT_EQ(preset->GetName(), info.preset_name);
1591 }
1592 }
1593
TEST_F(HasClientTest,test_discovery_basic_has_no_opt_ntf)1594 TEST_F(HasClientTest, test_discovery_basic_has_no_opt_ntf) {
1595 const RawAddress test_address = GetTestAddress(1);
1596 auto test_conn_id = GetTestConnId(test_address);
1597
1598 SetSampleDatabaseHasNoOptionalNtf(test_address);
1599
1600 std::variant<RawAddress, int> addr_or_group = test_address;
1601 std::vector<PresetInfo> preset_details;
1602 uint8_t active_preset_index;
1603 uint8_t has_features;
1604
1605 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1606 .WillOnce(SaveArg<1>(&has_features));
1607 EXPECT_CALL(*callbacks,
1608 OnConnectionState(ConnectionState::CONNECTED, test_address));
1609 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1610 .WillOnce(DoAll(SaveArg<0>(&addr_or_group), SaveArg<2>(&preset_details)));
1611 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
1612 .WillOnce(
1613 DoAll(SaveArg<0>(&addr_or_group), SaveArg<1>(&active_preset_index)));
1614 TestConnect(test_address);
1615
1616 /* Verify sample database content */
1617 ASSERT_TRUE(std::holds_alternative<RawAddress>(addr_or_group));
1618 ASSERT_EQ(std::get<RawAddress>(addr_or_group), test_address);
1619 ASSERT_EQ(has_features, 0x00);
1620 ASSERT_EQ(active_preset_index,
1621 current_peer_presets_.at(test_conn_id).begin()->GetIndex());
1622
1623 /* Verify presets */
1624 uint16_t conn_id = GetTestConnId(test_address);
1625 ASSERT_NE(preset_details.size(), 0u);
1626 ASSERT_EQ(current_peer_presets_.at(conn_id).size(), preset_details.size());
1627
1628 for (auto const& preset : current_peer_presets_.at(conn_id)) {
1629 auto it =
1630 std::find_if(preset_details.cbegin(), preset_details.cend(),
1631 [&preset](auto const& preset_info) {
1632 return preset_info.preset_index == preset.GetIndex();
1633 });
1634 ASSERT_NE(it, preset_details.cend());
1635 ASSERT_EQ(preset.GetName(), it->preset_name);
1636 ASSERT_EQ(preset.IsAvailable(), it->available);
1637 ASSERT_EQ(preset.IsWritable(), it->writable);
1638 }
1639
1640 /* Verify active preset is there */
1641 ASSERT_EQ(preset_details.size(),
1642 current_peer_presets_.at(test_conn_id).size());
1643 ASSERT_TRUE(std::find_if(preset_details.begin(), preset_details.end(),
1644 [active_preset_index](auto const& preset_info) {
1645 return preset_info.preset_index ==
1646 active_preset_index;
1647 }) != preset_details.end());
1648 }
1649
TEST_F(HasClientTest,test_discovery_has_not_found)1650 TEST_F(HasClientTest, test_discovery_has_not_found) {
1651 const RawAddress test_address = GetTestAddress(1);
1652 SetSampleDatabaseNoHas(test_address);
1653
1654 EXPECT_CALL(*callbacks,
1655 OnConnectionState(ConnectionState::CONNECTED, test_address))
1656 .Times(0);
1657 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(0);
1658 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _)).Times(0);
1659 EXPECT_CALL(*callbacks,
1660 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1661
1662 TestConnect(test_address);
1663 }
1664
TEST_F(HasClientTest,test_discovery_has_broken_no_active_preset)1665 TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset) {
1666 const RawAddress test_address = GetTestAddress(1);
1667 SetSampleDatabaseHasBrokenNoActivePreset(test_address);
1668
1669 EXPECT_CALL(*callbacks,
1670 OnConnectionState(ConnectionState::CONNECTED, test_address))
1671 .Times(0);
1672 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(0);
1673 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _)).Times(0);
1674 EXPECT_CALL(*callbacks,
1675 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1676
1677 TestConnect(test_address);
1678 }
1679
TEST_F(HasClientTest,test_discovery_has_broken_no_active_preset_ntf)1680 TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset_ntf) {
1681 const RawAddress test_address = GetTestAddress(1);
1682 SetSampleDatabaseHasBrokenNoActivePresetNtf(test_address);
1683
1684 EXPECT_CALL(*callbacks,
1685 OnConnectionState(ConnectionState::CONNECTED, test_address))
1686 .Times(0);
1687 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(0);
1688 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _)).Times(0);
1689 EXPECT_CALL(*callbacks,
1690 OnConnectionState(ConnectionState::DISCONNECTED, test_address));
1691
1692 TestConnect(test_address);
1693 }
1694
TEST_F(HasClientTest,test_discovery_has_features_ntf)1695 TEST_F(HasClientTest, test_discovery_has_features_ntf) {
1696 const RawAddress test_address = GetTestAddress(1);
1697 auto test_conn_id = GetTestConnId(test_address);
1698 uint8_t has_features;
1699
1700 SetSampleDatabaseHasOnlyFeaturesNtf(
1701 test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1702
1703 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1704 .WillOnce(SaveArg<1>(&has_features));
1705 EXPECT_CALL(*callbacks,
1706 OnConnectionState(ConnectionState::CONNECTED, test_address))
1707 .Times(1);
1708
1709 /* Verify subscription to features */
1710 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1711 .Times(AnyNumber());
1712 EXPECT_CALL(gatt_interface,
1713 RegisterForNotifications(gatt_if, test_address,
1714 HasDbBuilder::kFeaturesValHdl));
1715
1716 /* Verify features CCC was written */
1717 EXPECT_CALL(gatt_queue, WriteDescriptor(test_conn_id, _, _, _, _, _))
1718 .Times(AnyNumber());
1719 EXPECT_CALL(gatt_queue,
1720 WriteDescriptor(test_conn_id, HasDbBuilder::kFeaturesValHdl + 1,
1721 std::vector<uint8_t>{0x01, 0x00}, _, _, _));
1722 TestConnect(test_address);
1723
1724 /* Verify features */
1725 ASSERT_EQ(has_features, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1726
1727 uint8_t new_features;
1728
1729 /* Verify peer features change notification */
1730 EXPECT_CALL(*callbacks, OnFeaturesUpdate(test_address, _))
1731 .WillOnce(SaveArg<1>(&new_features));
1732 InjectNotificationEvent(test_address, test_conn_id,
1733 HasDbBuilder::kFeaturesValHdl,
1734 std::vector<uint8_t>({0x00}));
1735 ASSERT_NE(has_features, new_features);
1736 }
1737
TEST_F(HasClientTest,test_discovery_has_features_no_ntf)1738 TEST_F(HasClientTest, test_discovery_has_features_no_ntf) {
1739 const RawAddress test_address = GetTestAddress(1);
1740 auto test_conn_id = GetTestConnId(test_address);
1741 uint8_t has_features;
1742
1743 SetSampleDatabaseHasOnlyFeaturesNoNtf(
1744 test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1745
1746 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1747 .WillOnce(SaveArg<1>(&has_features));
1748 EXPECT_CALL(*callbacks,
1749 OnConnectionState(ConnectionState::CONNECTED, test_address))
1750 .Times(1);
1751
1752 /* Verify no subscription to features */
1753 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1754 .Times(AnyNumber());
1755 EXPECT_CALL(gatt_interface,
1756 RegisterForNotifications(gatt_if, test_address,
1757 HasDbBuilder::kFeaturesValHdl))
1758 .Times(0);
1759
1760 /* Verify no features CCC was written */
1761 EXPECT_CALL(gatt_queue, WriteDescriptor(test_conn_id, _, _, _, _, _))
1762 .Times(AnyNumber());
1763 EXPECT_CALL(gatt_queue,
1764 WriteDescriptor(test_conn_id, HasDbBuilder::kFeaturesValHdl + 1,
1765 _, _, _, _))
1766 .Times(0);
1767 TestConnect(test_address);
1768
1769 /* Verify features */
1770 ASSERT_EQ(has_features, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1771 }
1772
TEST_F(HasClientTest,test_discovery_has_multiple_presets_ntf)1773 TEST_F(HasClientTest, test_discovery_has_multiple_presets_ntf) {
1774 const RawAddress test_address = GetTestAddress(1);
1775 SetSampleDatabaseHasPresetsNtf(
1776 test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1777
1778 std::variant<RawAddress, int> addr_or_group = test_address;
1779 std::vector<PresetInfo> preset_details;
1780 uint8_t active_preset_index;
1781 uint8_t has_features;
1782
1783 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _))
1784 .WillOnce(SaveArg<1>(&has_features));
1785 EXPECT_CALL(*callbacks,
1786 OnConnectionState(ConnectionState::CONNECTED, test_address));
1787 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1788 .WillOnce(DoAll(SaveArg<0>(&addr_or_group), SaveArg<2>(&preset_details)));
1789 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
1790 .WillOnce(
1791 DoAll(SaveArg<0>(&addr_or_group), SaveArg<1>(&active_preset_index)));
1792
1793 /* Verify subscription to control point */
1794 EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
1795 .Times(AnyNumber());
1796 EXPECT_CALL(gatt_interface,
1797 RegisterForNotifications(gatt_if, test_address,
1798 HasDbBuilder::kPresetsCtpValHdl));
1799
1800 /* Verify features CCC was written */
1801 EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(AnyNumber());
1802 EXPECT_CALL(gatt_queue,
1803 WriteDescriptor(1, HasDbBuilder::kPresetsCtpValHdl + 1,
1804 std::vector<uint8_t>{0x03, 0x00}, _, _, _));
1805 TestConnect(test_address);
1806
1807 /* Verify features */
1808 ASSERT_EQ(has_features, bluetooth::has::kFeatureBitHearingAidTypeBanded);
1809 }
1810
TEST_F(HasClientTest,test_active_preset_change)1811 TEST_F(HasClientTest, test_active_preset_change) {
1812 const RawAddress test_address = GetTestAddress(1);
1813 auto test_conn_id = GetTestConnId(test_address);
1814
1815 SetSampleDatabaseHasNoOptionalNtf(test_address);
1816
1817 uint8_t active_preset_index;
1818 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _));
1819 EXPECT_CALL(*callbacks,
1820 OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _));
1821 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
1822 .WillOnce(SaveArg<1>(&active_preset_index));
1823 EXPECT_CALL(*callbacks,
1824 OnConnectionState(ConnectionState::CONNECTED, test_address));
1825 TestConnect(test_address);
1826
1827 uint8_t new_active_preset;
1828 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1829 std::variant<RawAddress, int>(test_address), _))
1830 .WillOnce(SaveArg<1>(&new_active_preset));
1831 InjectNotificationEvent(test_address, test_conn_id,
1832 HasDbBuilder::kActivePresetIndexValHdl,
1833 std::vector<uint8_t>({0x00}));
1834
1835 ASSERT_NE(active_preset_index, new_active_preset);
1836 ASSERT_EQ(new_active_preset, 0x00);
1837 }
1838
TEST_F(HasClientTest,test_duplicate_presets)1839 TEST_F(HasClientTest, test_duplicate_presets) {
1840 const RawAddress test_address = GetTestAddress(1);
1841 std::vector<PresetInfo> preset_details;
1842
1843 /* Handle duplicates gracefully */
1844 SetSampleDatabaseHasPresetsNtf(
1845 test_address, kFeatureBitWritablePresets,
1846 {{HasPreset(5,
1847 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1848 "YourWritablePreset5"),
1849 HasPreset(5,
1850 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1851 "YourWritablePreset5")}});
1852
1853 EXPECT_CALL(*callbacks,
1854 OnConnectionState(ConnectionState::CONNECTED, test_address));
1855 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
1856 .WillOnce(SaveArg<2>(&preset_details));
1857 TestConnect(test_address);
1858
1859 /* Verify presets - expect 1, no duplicates */
1860 ASSERT_EQ(preset_details.size(), 1u);
1861 auto preset = std::find_if(
1862 preset_details.begin(), preset_details.end(),
1863 [](auto const& preset_info) { return preset_info.preset_index == 5; });
1864 ASSERT_TRUE(preset != preset_details.end());
1865 ASSERT_EQ("YourWritablePreset5", preset->preset_name);
1866 ASSERT_TRUE(preset->available);
1867 ASSERT_TRUE(preset->writable);
1868 }
1869
TEST_F(HasClientTest,test_preset_set_name_invalid_index)1870 TEST_F(HasClientTest, test_preset_set_name_invalid_index) {
1871 const RawAddress test_address = GetTestAddress(1);
1872 SetSampleDatabaseHasPresetsNtf(test_address);
1873 TestConnect(test_address);
1874
1875 EXPECT_CALL(*callbacks,
1876 OnSetPresetNameError(std::variant<RawAddress, int>(test_address),
1877 0x40, ErrorCode::INVALID_PRESET_INDEX))
1878 .Times(1);
1879 EXPECT_CALL(gatt_queue,
1880 WriteCharacteristic(1, HasDbBuilder::kPresetsCtpValHdl, _,
1881 GATT_WRITE, _, _))
1882 .Times(0);
1883
1884 HasClient::Get()->SetPresetName(test_address, 0x40, "new preset name");
1885 }
1886
TEST_F(HasClientTest,test_preset_set_name_non_writable)1887 TEST_F(HasClientTest, test_preset_set_name_non_writable) {
1888 const RawAddress test_address = GetTestAddress(1);
1889 uint16_t test_conn_id = GetTestConnId(test_address);
1890
1891 SetSampleDatabaseHasPresetsNtf(
1892 test_address, kFeatureBitWritablePresets,
1893 {{
1894 HasPreset(5, HasPreset::kPropertyAvailable, "YourPreset5"),
1895 HasPreset(
1896 55, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1897 "YourWritablePreset55"),
1898 }});
1899 TestConnect(test_address);
1900
1901 EXPECT_CALL(*callbacks,
1902 OnSetPresetNameError(_, _, ErrorCode::SET_NAME_NOT_ALLOWED))
1903 .Times(1);
1904 EXPECT_CALL(gatt_queue,
1905 WriteCharacteristic(1, HasDbBuilder::kPresetsCtpValHdl, _,
1906 GATT_WRITE, _, _))
1907 .Times(0);
1908
1909 HasClient::Get()->SetPresetName(
1910 test_address, current_peer_presets_.at(test_conn_id).begin()->GetIndex(),
1911 "new preset name");
1912 }
1913
TEST_F(HasClientTest,test_preset_set_name_to_long)1914 TEST_F(HasClientTest, test_preset_set_name_to_long) {
1915 const RawAddress test_address = GetTestAddress(1);
1916 uint16_t test_conn_id = GetTestConnId(test_address);
1917
1918 SetSampleDatabaseHasPresetsNtf(
1919 test_address, kFeatureBitWritablePresets,
1920 {{HasPreset(5,
1921 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1922 "YourWritablePreset")}});
1923 TestConnect(test_address);
1924
1925 EXPECT_CALL(*callbacks,
1926 OnSetPresetNameError(_, _, ErrorCode::INVALID_PRESET_NAME_LENGTH))
1927 .Times(1);
1928 EXPECT_CALL(gatt_queue,
1929 WriteCharacteristic(test_conn_id, HasDbBuilder::kPresetsCtpValHdl,
1930 _, GATT_WRITE, _, _))
1931 .Times(0);
1932
1933 HasClient::Get()->SetPresetName(test_address, 5,
1934 "this name is more than 40 characters long");
1935 }
1936
TEST_F(HasClientTest,test_preset_set_name)1937 TEST_F(HasClientTest, test_preset_set_name) {
1938 const RawAddress test_address = GetTestAddress(1);
1939 uint16_t test_conn_id = GetTestConnId(test_address);
1940
1941 SetSampleDatabaseHasPresetsNtf(
1942 test_address, kFeatureBitWritablePresets,
1943 {{HasPreset(5,
1944 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
1945 "YourWritablePreset5")}});
1946
1947 TestConnect(test_address);
1948
1949 std::vector<uint8_t> value;
1950 EXPECT_CALL(*callbacks, OnSetPresetNameError(_, _, _)).Times(0);
1951 EXPECT_CALL(gatt_queue,
1952 WriteCharacteristic(test_conn_id, HasDbBuilder::kPresetsCtpValHdl,
1953 _, GATT_WRITE, _, _));
1954
1955 std::vector<PresetInfo> updated_preset_details;
1956 EXPECT_CALL(*callbacks,
1957 OnPresetInfo(std::variant<RawAddress, int>(test_address),
1958 PresetInfoReason::PRESET_INFO_UPDATE, _))
1959 .WillOnce(SaveArg<2>(&updated_preset_details));
1960 HasClient::Get()->SetPresetName(test_address, 5, "new preset name");
1961
1962 ASSERT_EQ(1u, updated_preset_details.size());
1963 ASSERT_EQ(updated_preset_details[0].preset_name, "new preset name");
1964 }
1965
TEST_F(HasClientTest,test_preset_group_set_name)1966 TEST_F(HasClientTest, test_preset_group_set_name) {
1967 /* None of these devices support preset syncing */
1968 const RawAddress test_address1 = GetTestAddress(1);
1969 SetSampleDatabaseHasPresetsNtf(
1970 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural |
1971 bluetooth::has::kFeatureBitWritablePresets);
1972
1973 const RawAddress test_address2 = GetTestAddress(2);
1974 SetSampleDatabaseHasPresetsNtf(
1975 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural |
1976 bluetooth::has::kFeatureBitWritablePresets);
1977
1978 TestConnect(test_address1);
1979 TestConnect(test_address2);
1980
1981 /* Mock the csis group with two devices */
1982 uint8_t not_synced_group = 13;
1983 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
1984 .WillByDefault(
1985 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
1986 ON_CALL(
1987 mock_csis_client_module_,
1988 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
1989 .WillByDefault(Return(not_synced_group));
1990 ON_CALL(
1991 mock_csis_client_module_,
1992 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
1993 .WillByDefault(Return(not_synced_group));
1994
1995 std::vector<PresetInfo> preset_details;
1996 EXPECT_CALL(*callbacks, OnActivePresetSelected(
1997 std::variant<RawAddress, int>(test_address1), 55))
1998 .Times(0);
1999 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2000 std::variant<RawAddress, int>(test_address2), 55))
2001 .Times(0);
2002
2003 /* This should be a group callback */
2004 EXPECT_CALL(*callbacks,
2005 OnPresetInfo(std::variant<RawAddress, int>(not_synced_group),
2006 PresetInfoReason::PRESET_INFO_UPDATE, _))
2007 .Times(1)
2008 .WillOnce(SaveArg<2>(&preset_details));
2009
2010 /* No locally synced opcodes support so expect both devices getting writes */
2011 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2012 HasDbBuilder::kPresetsCtpValHdl,
2013 _, GATT_WRITE, _, _))
2014 .Times(1);
2015 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2016 HasDbBuilder::kPresetsCtpValHdl,
2017 _, GATT_WRITE, _, _))
2018 .Times(1);
2019
2020 HasClient::Get()->SetPresetName(not_synced_group, 55, "new preset name");
2021 ASSERT_EQ(preset_details.size(), 1u);
2022 ASSERT_EQ(preset_details[0].preset_name, "new preset name");
2023 ASSERT_EQ(preset_details[0].preset_index, 55);
2024 }
2025
TEST_F(HasClientTest,test_multiple_presets_get_name)2026 TEST_F(HasClientTest, test_multiple_presets_get_name) {
2027 const RawAddress test_address = GetTestAddress(1);
2028 SetSampleDatabaseHasPresetsNtf(
2029 test_address, kFeatureBitWritablePresets,
2030 {{
2031 HasPreset(
2032 5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2033 "YourWritablePreset5"),
2034 HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
2035 HasPreset(99, 0, "YourPreset99"),
2036 }});
2037
2038 std::vector<PresetInfo> preset_details;
2039
2040 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _));
2041 EXPECT_CALL(*callbacks,
2042 OnConnectionState(ConnectionState::CONNECTED, test_address));
2043 EXPECT_CALL(*callbacks, OnPresetInfo(_, PresetInfoReason::ALL_PRESET_INFO, _))
2044 .WillOnce(SaveArg<2>(&preset_details));
2045 TestConnect(test_address);
2046
2047 /* Get each preset info individually */
2048 for (auto const& preset : preset_details) {
2049 std::vector<PresetInfo> new_preset_details;
2050
2051 EXPECT_CALL(*callbacks,
2052 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2053 PresetInfoReason::PRESET_INFO_REQUEST_RESPONSE, _))
2054 .Times(1)
2055 .WillOnce(SaveArg<2>(&new_preset_details));
2056 HasClient::Get()->GetPresetInfo(test_address, preset.preset_index);
2057
2058 Mock::VerifyAndClearExpectations(&*callbacks);
2059 ASSERT_EQ(1u, new_preset_details.size());
2060 ASSERT_EQ(preset.preset_index, new_preset_details[0].preset_index);
2061 ASSERT_EQ(preset.preset_name, new_preset_details[0].preset_name);
2062 ASSERT_EQ(preset.writable, new_preset_details[0].writable);
2063 ASSERT_EQ(preset.available, new_preset_details[0].available);
2064 }
2065 }
2066
TEST_F(HasClientTest,test_presets_get_name_invalid_index)2067 TEST_F(HasClientTest, test_presets_get_name_invalid_index) {
2068 const RawAddress test_address = GetTestAddress(1);
2069 SetSampleDatabaseHasPresetsNtf(test_address);
2070 TestConnect(test_address);
2071
2072 EXPECT_CALL(*callbacks,
2073 OnPresetInfoError(std::variant<RawAddress, int>(test_address),
2074 128, ErrorCode::INVALID_PRESET_INDEX));
2075 HasClient::Get()->GetPresetInfo(test_address, 128);
2076
2077 EXPECT_CALL(*callbacks,
2078 OnPresetInfoError(std::variant<RawAddress, int>(test_address), 0,
2079 ErrorCode::INVALID_PRESET_INDEX));
2080 HasClient::Get()->GetPresetInfo(test_address, 0);
2081 }
2082
TEST_F(HasClientTest,test_presets_changed_generic_update_no_add_or_delete)2083 TEST_F(HasClientTest, test_presets_changed_generic_update_no_add_or_delete) {
2084 const RawAddress test_address = GetTestAddress(1);
2085 uint16_t test_conn_id = GetTestConnId(test_address);
2086
2087 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2088 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2089 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2090 "Preset2"),
2091 HasPreset(4, HasPreset::kPropertyAvailable, "Preset4"),
2092 HasPreset(7, HasPreset::kPropertyAvailable, "Preset7"),
2093 }};
2094 SetSampleDatabaseHasPresetsNtf(
2095 test_address,
2096 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2097 bluetooth::has::kFeatureBitDynamicPresets |
2098 bluetooth::has::kFeatureBitWritablePresets,
2099 presets);
2100
2101 EXPECT_CALL(*callbacks,
2102 OnConnectionState(ConnectionState::CONNECTED, test_address));
2103 TestConnect(test_address);
2104
2105 std::vector<PresetInfo> preset_details;
2106 EXPECT_CALL(*callbacks,
2107 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2108 PresetInfoReason::PRESET_INFO_UPDATE, _))
2109 .Times(1)
2110 .WillOnce(SaveArg<2>(&preset_details));
2111
2112 /* Inject generic update on the first preset */
2113 auto preset_index = 2;
2114 auto new_test_preset = HasPreset(preset_index, 0, "props new name");
2115 ASSERT_NE(*current_peer_presets_.at(test_conn_id).find(preset_index),
2116 new_test_preset);
2117
2118 InjectPresetChanged(
2119 test_conn_id, test_address, false, new_test_preset, 1 /* prev_index */,
2120 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2121 true /* is_last */);
2122
2123 /* Verify received preset info update on the 2nd preset */
2124 ASSERT_EQ(1u, preset_details.size());
2125 ASSERT_EQ(new_test_preset.GetIndex(), preset_details[0].preset_index);
2126 ASSERT_EQ(new_test_preset.IsAvailable(), preset_details[0].available);
2127 ASSERT_EQ(new_test_preset.IsWritable(), preset_details[0].writable);
2128 ASSERT_EQ(new_test_preset.GetName(), preset_details[0].preset_name);
2129 }
2130
TEST_F(HasClientTest,test_presets_changed_generic_update_add_and_delete)2131 TEST_F(HasClientTest, test_presets_changed_generic_update_add_and_delete) {
2132 const RawAddress test_address = GetTestAddress(1);
2133 uint16_t test_conn_id = GetTestConnId(test_address);
2134
2135 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2136 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2137 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2138 "Preset2"),
2139 HasPreset(4, HasPreset::kPropertyAvailable, "Preset4"),
2140 HasPreset(5, HasPreset::kPropertyAvailable, "Preset5"),
2141 HasPreset(32, HasPreset::kPropertyAvailable, "Preset32"),
2142 }};
2143 SetSampleDatabaseHasPresetsNtf(
2144 test_address,
2145 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2146 bluetooth::has::kFeatureBitWritablePresets,
2147 presets);
2148
2149 std::vector<PresetInfo> preset_details;
2150 EXPECT_CALL(*callbacks,
2151 OnConnectionState(ConnectionState::CONNECTED, test_address));
2152 EXPECT_CALL(*callbacks,
2153 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2154 PresetInfoReason::ALL_PRESET_INFO, _))
2155 .Times(1)
2156 .WillOnce(SaveArg<2>(&preset_details));
2157 TestConnect(test_address);
2158
2159 /* Expect more OnPresetInfo call */
2160 std::vector<PresetInfo> updated_preset_details;
2161 EXPECT_CALL(*callbacks,
2162 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2163 PresetInfoReason::PRESET_INFO_UPDATE, _))
2164 .Times(1)
2165 .WillOnce(SaveArg<2>(&updated_preset_details));
2166
2167 /* Expect more OnPresetInfo call */
2168 std::vector<PresetInfo> deleted_preset_details;
2169 EXPECT_CALL(*callbacks,
2170 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2171 PresetInfoReason::PRESET_DELETED, _))
2172 .Times(1)
2173 .WillOnce(SaveArg<2>(&deleted_preset_details));
2174
2175 /* Inject generic updates */
2176 /* First event replaces all the existing presets from 1 to 8 with preset 8
2177 */
2178 auto new_test_preset1 =
2179 HasPreset(8, HasPreset::kPropertyAvailable, "props new name9");
2180 InjectPresetChanged(
2181 test_conn_id, test_address, false, new_test_preset1, 1 /* prev_index */,
2182 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2183 false /* is_last */);
2184
2185 /* Second event adds preset 9 to the already existing presets 1 and 8 */
2186 auto new_test_preset2 =
2187 HasPreset(9, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2188 "props new name11");
2189 InjectPresetChanged(
2190 test_conn_id, test_address, false, new_test_preset2, 8 /* prev_index */,
2191 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2192 false /* is_last */);
2193
2194 /* Third event deletes preset 1 with the generic update */
2195 InjectPresetChanged(
2196 test_conn_id, test_address, false, new_test_preset1, 0 /* prev_index */,
2197 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_GENERIC_UPDATE,
2198 true /* is_last */);
2199
2200 /* Verify received preset info - expect presets 1, 32 unchanged, 8, 9
2201 * updated, and 1, 2, 4, 5 deleted.
2202 */
2203 ASSERT_EQ(2u, updated_preset_details.size());
2204 ASSERT_EQ(new_test_preset1.GetIndex(),
2205 updated_preset_details[0].preset_index);
2206 ASSERT_EQ(new_test_preset1.IsAvailable(),
2207 updated_preset_details[0].available);
2208 ASSERT_EQ(new_test_preset1.IsWritable(), updated_preset_details[0].writable);
2209 ASSERT_EQ(new_test_preset1.GetName(), updated_preset_details[0].preset_name);
2210 ASSERT_EQ(new_test_preset2.GetIndex(),
2211 updated_preset_details[1].preset_index);
2212 ASSERT_EQ(new_test_preset2.IsAvailable(),
2213 updated_preset_details[1].available);
2214 ASSERT_EQ(new_test_preset2.IsWritable(), updated_preset_details[1].writable);
2215 ASSERT_EQ(new_test_preset2.GetName(), updated_preset_details[1].preset_name);
2216
2217 ASSERT_EQ(4u, deleted_preset_details.size());
2218 ASSERT_EQ(2, deleted_preset_details[0].preset_index);
2219 ASSERT_EQ(4, deleted_preset_details[1].preset_index);
2220 ASSERT_EQ(5, deleted_preset_details[2].preset_index);
2221 ASSERT_EQ(1, deleted_preset_details[3].preset_index);
2222 }
2223
TEST_F(HasClientTest,test_presets_changed_deleted)2224 TEST_F(HasClientTest, test_presets_changed_deleted) {
2225 const RawAddress test_address = GetTestAddress(1);
2226 uint16_t test_conn_id = GetTestConnId(test_address);
2227
2228 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2229 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2230 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2231 "Preset2"),
2232 }};
2233 SetSampleDatabaseHasPresetsNtf(
2234 test_address,
2235 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2236 bluetooth::has::kFeatureBitWritablePresets |
2237 bluetooth::has::kFeatureBitDynamicPresets,
2238 presets);
2239
2240 std::vector<PresetInfo> preset_details;
2241 EXPECT_CALL(*callbacks,
2242 OnConnectionState(ConnectionState::CONNECTED, test_address));
2243 EXPECT_CALL(*callbacks,
2244 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2245 PresetInfoReason::ALL_PRESET_INFO, _))
2246 .Times(1)
2247 .WillOnce(SaveArg<2>(&preset_details));
2248 TestConnect(test_address);
2249
2250 /* Expect second OnPresetInfo call */
2251 std::vector<PresetInfo> deleted_preset_details;
2252 EXPECT_CALL(*callbacks,
2253 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2254 PresetInfoReason::PRESET_DELETED, _))
2255 .Times(1)
2256 .WillOnce(SaveArg<2>(&deleted_preset_details));
2257
2258 /* Inject preset deletion of index 2 */
2259 auto deleted_index = preset_details[1].preset_index;
2260 InjectPresetChanged(
2261 test_conn_id, test_address, false, *presets.find(deleted_index),
2262 0 /* prev_index */,
2263 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_DELETED,
2264 true /* is_last */);
2265
2266 ASSERT_EQ(2u, preset_details.size());
2267 ASSERT_EQ(1u, deleted_preset_details.size());
2268 ASSERT_EQ(preset_details[1].preset_index,
2269 deleted_preset_details[0].preset_index);
2270 ASSERT_EQ(preset_details[1].writable, deleted_preset_details[0].writable);
2271 ASSERT_EQ(preset_details[1].available, deleted_preset_details[0].available);
2272 ASSERT_EQ(preset_details[1].preset_name,
2273 deleted_preset_details[0].preset_name);
2274 }
2275
TEST_F(HasClientTest,test_presets_changed_available)2276 TEST_F(HasClientTest, test_presets_changed_available) {
2277 const RawAddress test_address = GetTestAddress(1);
2278 uint16_t test_conn_id = GetTestConnId(test_address);
2279
2280 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2281 HasPreset(1, 0, "Universal"),
2282 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2283 "Preset2"),
2284 }};
2285 SetSampleDatabaseHasPresetsNtf(
2286 test_address,
2287 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2288 bluetooth::has::kFeatureBitWritablePresets |
2289 bluetooth::has::kFeatureBitDynamicPresets,
2290 presets);
2291
2292 std::vector<PresetInfo> preset_details;
2293 EXPECT_CALL(*callbacks,
2294 OnConnectionState(ConnectionState::CONNECTED, test_address));
2295 EXPECT_CALL(*callbacks,
2296 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2297 PresetInfoReason::ALL_PRESET_INFO, _))
2298 .Times(1)
2299 .WillOnce(SaveArg<2>(&preset_details));
2300 TestConnect(test_address);
2301
2302 /* Expect second OnPresetInfo call */
2303 std::vector<PresetInfo> changed_preset_details;
2304 EXPECT_CALL(*callbacks,
2305 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2306 PresetInfoReason::PRESET_AVAILABILITY_CHANGED, _))
2307 .Times(1)
2308 .WillOnce(SaveArg<2>(&changed_preset_details));
2309
2310 /* Inject preset deletion of index 2 */
2311 auto changed_index = preset_details[0].preset_index;
2312 InjectPresetChanged(
2313 test_conn_id, test_address, false, *presets.find(changed_index),
2314 0 /* prev_index */,
2315 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_AVAILABLE,
2316 true /* is_last */);
2317
2318 ASSERT_EQ(2u, preset_details.size());
2319 ASSERT_EQ(1u, changed_preset_details.size());
2320 ASSERT_EQ(preset_details[0].preset_index,
2321 changed_preset_details[0].preset_index);
2322 ASSERT_EQ(preset_details[0].writable, changed_preset_details[0].writable);
2323 ASSERT_EQ(preset_details[0].preset_name,
2324 changed_preset_details[0].preset_name);
2325 /* This field should have changed */
2326 ASSERT_NE(preset_details[0].available, changed_preset_details[0].available);
2327 ASSERT_TRUE(changed_preset_details[0].available);
2328 }
2329
TEST_F(HasClientTest,test_presets_changed_unavailable)2330 TEST_F(HasClientTest, test_presets_changed_unavailable) {
2331 const RawAddress test_address = GetTestAddress(1);
2332 uint16_t test_conn_id = GetTestConnId(test_address);
2333
2334 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2335 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2336 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2337 "Preset2"),
2338 }};
2339 SetSampleDatabaseHasPresetsNtf(
2340 test_address,
2341 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2342 bluetooth::has::kFeatureBitWritablePresets |
2343 bluetooth::has::kFeatureBitDynamicPresets,
2344 presets);
2345
2346 std::vector<PresetInfo> preset_details;
2347 EXPECT_CALL(*callbacks,
2348 OnConnectionState(ConnectionState::CONNECTED, test_address));
2349 EXPECT_CALL(*callbacks,
2350 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2351 PresetInfoReason::ALL_PRESET_INFO, _))
2352 .Times(1)
2353 .WillOnce(SaveArg<2>(&preset_details));
2354 TestConnect(test_address);
2355
2356 /* Expect second OnPresetInfo call */
2357 std::vector<PresetInfo> changed_preset_details;
2358 EXPECT_CALL(*callbacks,
2359 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2360 PresetInfoReason::PRESET_AVAILABILITY_CHANGED, _))
2361 .Times(1)
2362 .WillOnce(SaveArg<2>(&changed_preset_details));
2363
2364 /* Inject preset deletion of index 2 */
2365 auto changed_index = preset_details[0].preset_index;
2366 InjectPresetChanged(
2367 test_conn_id, test_address, false, *presets.find(changed_index),
2368 0 /* prev_index */,
2369 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_UNAVAILABLE,
2370 true /* is_last */);
2371
2372 ASSERT_EQ(2u, preset_details.size());
2373 ASSERT_EQ(1u, changed_preset_details.size());
2374 ASSERT_EQ(preset_details[0].preset_index,
2375 changed_preset_details[0].preset_index);
2376 ASSERT_EQ(preset_details[0].writable, changed_preset_details[0].writable);
2377 ASSERT_EQ(preset_details[0].preset_name,
2378 changed_preset_details[0].preset_name);
2379 /* This field should have changed */
2380 ASSERT_NE(preset_details[0].available, changed_preset_details[0].available);
2381 ASSERT_FALSE(changed_preset_details[0].available);
2382 }
2383
TEST_F(HasClientTest,test_select_preset_valid)2384 TEST_F(HasClientTest, test_select_preset_valid) {
2385 const RawAddress test_address = GetTestAddress(1);
2386 SetSampleDatabaseHasPresetsNtf(test_address);
2387
2388 uint8_t active_preset_index = 0;
2389 std::vector<PresetInfo> preset_details;
2390
2391 EXPECT_CALL(*callbacks,
2392 OnConnectionState(ConnectionState::CONNECTED, test_address));
2393 EXPECT_CALL(*callbacks,
2394 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2395 PresetInfoReason::ALL_PRESET_INFO, _))
2396 .Times(1)
2397 .WillOnce(SaveArg<2>(&preset_details));
2398 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2399 .WillOnce(SaveArg<1>(&active_preset_index));
2400 TestConnect(test_address);
2401
2402 ASSERT_TRUE(preset_details.size() > 1);
2403 ASSERT_EQ(preset_details.front().preset_index, active_preset_index);
2404
2405 uint8_t new_active_preset_index = 0;
2406 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2407 .WillOnce(SaveArg<1>(&new_active_preset_index));
2408
2409 HasClient::Get()->SelectActivePreset(test_address,
2410 preset_details.back().preset_index);
2411 Mock::VerifyAndClearExpectations(&*callbacks);
2412
2413 ASSERT_NE(active_preset_index, new_active_preset_index);
2414 ASSERT_EQ(preset_details.back().preset_index, new_active_preset_index);
2415 }
2416
TEST_F(HasClientTest,test_select_group_preset_invalid_group)2417 TEST_F(HasClientTest, test_select_group_preset_invalid_group) {
2418 const RawAddress test_address1 = GetTestAddress(1);
2419 SetSampleDatabaseHasPresetsNtf(test_address1);
2420
2421 const RawAddress test_address2 = GetTestAddress(2);
2422 SetSampleDatabaseHasPresetsNtf(test_address2);
2423
2424 TestConnect(test_address1);
2425 TestConnect(test_address2);
2426
2427 /* Mock the csis group with no devices */
2428 uint8_t unlucky_group = 13;
2429 ON_CALL(mock_csis_client_module_, GetDeviceList(unlucky_group))
2430 .WillByDefault(Return(std::vector<RawAddress>()));
2431
2432 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2433 std::variant<RawAddress, int>(unlucky_group),
2434 ErrorCode::OPERATION_NOT_POSSIBLE))
2435 .Times(1);
2436
2437 HasClient::Get()->SelectActivePreset(unlucky_group, 6);
2438 }
2439
TEST_F(HasClientTest,test_select_group_preset_valid_no_preset_sync_supported)2440 TEST_F(HasClientTest, test_select_group_preset_valid_no_preset_sync_supported) {
2441 /* None of these devices support preset syncing */
2442 const RawAddress test_address1 = GetTestAddress(1);
2443 SetSampleDatabaseHasPresetsNtf(
2444 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2445
2446 const RawAddress test_address2 = GetTestAddress(2);
2447 SetSampleDatabaseHasPresetsNtf(
2448 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2449
2450 TestConnect(test_address1);
2451 TestConnect(test_address2);
2452
2453 /* Mock the csis group with two devices */
2454 uint8_t not_synced_group = 13;
2455 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
2456 .WillByDefault(
2457 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2458 ON_CALL(
2459 mock_csis_client_module_,
2460 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2461 .WillByDefault(Return(not_synced_group));
2462 ON_CALL(
2463 mock_csis_client_module_,
2464 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2465 .WillByDefault(Return(not_synced_group));
2466
2467 uint8_t group_active_preset_index = 0;
2468 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2469 std::variant<RawAddress, int>(test_address1), 55))
2470 .Times(0);
2471 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2472 std::variant<RawAddress, int>(test_address2), 55))
2473 .Times(0);
2474 EXPECT_CALL(*callbacks,
2475 OnActivePresetSelected(
2476 std::variant<RawAddress, int>(not_synced_group), _))
2477 .WillOnce(SaveArg<1>(&group_active_preset_index));
2478
2479 /* No locally synced opcodes support so expect both devices getting writes */
2480 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2481 HasDbBuilder::kPresetsCtpValHdl,
2482 _, GATT_WRITE, _, _))
2483 .Times(1);
2484 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2485 HasDbBuilder::kPresetsCtpValHdl,
2486 _, GATT_WRITE, _, _))
2487 .Times(1);
2488
2489 HasClient::Get()->SelectActivePreset(not_synced_group, 55);
2490 ASSERT_EQ(group_active_preset_index, 55);
2491 }
2492
TEST_F(HasClientTest,test_select_group_preset_valid_preset_sync_supported)2493 TEST_F(HasClientTest, test_select_group_preset_valid_preset_sync_supported) {
2494 /* Only one of these devices support preset syncing */
2495 const RawAddress test_address1 = GetTestAddress(1);
2496 uint16_t test_conn_id1 = GetTestConnId(test_address1);
2497 SetSampleDatabaseHasPresetsNtf(
2498 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2499
2500 const RawAddress test_address2 = GetTestAddress(2);
2501 uint16_t test_conn_id2 = GetTestConnId(test_address2);
2502 SetSampleDatabaseHasPresetsNtf(
2503 test_address2,
2504 bluetooth::has::kFeatureBitHearingAidTypeBinaural |
2505 bluetooth::has::kFeatureBitPresetSynchronizationSupported);
2506
2507 uint8_t active_preset_index1 = 0;
2508 uint8_t active_preset_index2 = 0;
2509
2510 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2511 std::variant<RawAddress, int>(test_address1), _))
2512 .WillOnce(SaveArg<1>(&active_preset_index1));
2513 TestConnect(test_address1);
2514
2515 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2516 std::variant<RawAddress, int>(test_address2), _))
2517 .WillOnce(SaveArg<1>(&active_preset_index2));
2518 TestConnect(test_address2);
2519
2520 /* Mock the csis group with two devices */
2521 uint8_t synced_group = 13;
2522 ON_CALL(mock_csis_client_module_, GetDeviceList(synced_group))
2523 .WillByDefault(
2524 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2525 ON_CALL(
2526 mock_csis_client_module_,
2527 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2528 .WillByDefault(Return(synced_group));
2529 ON_CALL(
2530 mock_csis_client_module_,
2531 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2532 .WillByDefault(Return(synced_group));
2533
2534 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2535 _, ErrorCode::GROUP_OPERATION_NOT_SUPPORTED))
2536 .Times(0);
2537
2538 /* Expect callback from the group but not from the devices */
2539 uint8_t group_active_preset_index = 0;
2540 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2541 std::variant<RawAddress, int>(test_address1), _))
2542 .Times(0);
2543 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2544 std::variant<RawAddress, int>(test_address2), _))
2545 .Times(0);
2546 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2547 std::variant<RawAddress, int>(synced_group), _))
2548 .WillOnce(SaveArg<1>(&group_active_preset_index));
2549
2550 /* Expect Ctp write on on this device which forwards operation to the other */
2551 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id1,
2552 HasDbBuilder::kPresetsCtpValHdl,
2553 _, GATT_WRITE, _, _))
2554 .Times(0);
2555 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id2,
2556 HasDbBuilder::kPresetsCtpValHdl,
2557 _, GATT_WRITE, _, _))
2558 .Times(1);
2559
2560 HasClient::Get()->SelectActivePreset(synced_group, 55);
2561 ASSERT_EQ(group_active_preset_index, 55);
2562 }
2563
TEST_F(HasClientTest,test_select_preset_invalid)2564 TEST_F(HasClientTest, test_select_preset_invalid) {
2565 const RawAddress test_address = GetTestAddress(1);
2566 uint16_t test_conn_id = GetTestConnId(test_address);
2567
2568 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2569 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2570 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2571 "Preset2"),
2572 }};
2573 SetSampleDatabaseHasPresetsNtf(
2574 test_address,
2575 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2576 bluetooth::has::kFeatureBitWritablePresets |
2577 bluetooth::has::kFeatureBitDynamicPresets,
2578 presets);
2579
2580 uint8_t active_preset_index = 0;
2581 std::vector<PresetInfo> preset_details;
2582
2583 EXPECT_CALL(*callbacks,
2584 OnConnectionState(ConnectionState::CONNECTED, test_address));
2585 EXPECT_CALL(*callbacks,
2586 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2587 PresetInfoReason::ALL_PRESET_INFO, _))
2588 .Times(1)
2589 .WillOnce(SaveArg<2>(&preset_details));
2590 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2591 .WillOnce(SaveArg<1>(&active_preset_index));
2592 TestConnect(test_address);
2593
2594 ASSERT_TRUE(preset_details.size() > 1);
2595 ASSERT_EQ(preset_details.front().preset_index, active_preset_index);
2596
2597 /* Inject preset deletion of index 2 */
2598 auto deleted_index = preset_details[1].preset_index;
2599 InjectPresetChanged(
2600 test_conn_id, test_address, false, *presets.find(deleted_index),
2601 0 /* prev_index */,
2602 ::bluetooth::le_audio::has::PresetCtpChangeId::PRESET_DELETED,
2603 true /* is_last */);
2604
2605 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2606 std::variant<RawAddress, int>(test_address),
2607 ErrorCode::INVALID_PRESET_INDEX))
2608 .Times(1);
2609
2610 /* Check if preset was actually deleted - try setting it as an active one */
2611 HasClient::Get()->SelectActivePreset(test_address,
2612 preset_details[1].preset_index);
2613 }
2614
TEST_F(HasClientTest,test_select_preset_next)2615 TEST_F(HasClientTest, test_select_preset_next) {
2616 const RawAddress test_address = GetTestAddress(1);
2617
2618 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2619 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2620 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2621 "Preset2"),
2622 }};
2623 SetSampleDatabaseHasPresetsNtf(
2624 test_address,
2625 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2626 bluetooth::has::kFeatureBitWritablePresets |
2627 bluetooth::has::kFeatureBitDynamicPresets,
2628 presets);
2629
2630 uint8_t active_preset_index = 0;
2631 std::vector<PresetInfo> preset_details;
2632
2633 EXPECT_CALL(*callbacks,
2634 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2635 PresetInfoReason::ALL_PRESET_INFO, _))
2636 .Times(1)
2637 .WillOnce(SaveArg<2>(&preset_details));
2638 EXPECT_CALL(*callbacks, OnActivePresetSelected(_, _))
2639 .WillOnce(SaveArg<1>(&active_preset_index));
2640 TestConnect(test_address);
2641
2642 ASSERT_TRUE(preset_details.size() > 1);
2643 ASSERT_EQ(1, active_preset_index);
2644
2645 /* Verify active preset change */
2646 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2647 std::variant<RawAddress, int>(test_address), 2));
2648 HasClient::Get()->NextActivePreset(test_address);
2649 }
2650
TEST_F(HasClientTest,test_select_group_preset_next_no_preset_sync_supported)2651 TEST_F(HasClientTest, test_select_group_preset_next_no_preset_sync_supported) {
2652 /* None of these devices support preset syncing */
2653 const RawAddress test_address1 = GetTestAddress(1);
2654 SetSampleDatabaseHasPresetsNtf(
2655 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2656
2657 const RawAddress test_address2 = GetTestAddress(2);
2658 SetSampleDatabaseHasPresetsNtf(
2659 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2660
2661 TestConnect(test_address1);
2662 TestConnect(test_address2);
2663
2664 /* Mock the csis group with two devices */
2665 uint8_t not_synced_group = 13;
2666 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
2667 .WillByDefault(
2668 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2669 ON_CALL(
2670 mock_csis_client_module_,
2671 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2672 .WillByDefault(Return(not_synced_group));
2673 ON_CALL(
2674 mock_csis_client_module_,
2675 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2676 .WillByDefault(Return(not_synced_group));
2677
2678 uint8_t group_active_preset_index = 0;
2679 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2680 std::variant<RawAddress, int>(test_address1), 55))
2681 .Times(0);
2682 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2683 std::variant<RawAddress, int>(test_address2), 55))
2684 .Times(0);
2685 EXPECT_CALL(*callbacks,
2686 OnActivePresetSelected(
2687 std::variant<RawAddress, int>(not_synced_group), _))
2688 .WillOnce(SaveArg<1>(&group_active_preset_index));
2689
2690 /* No locally synced opcodes support so expect both devices getting writes */
2691 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2692 HasDbBuilder::kPresetsCtpValHdl,
2693 _, GATT_WRITE, _, _))
2694 .Times(1);
2695 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2696 HasDbBuilder::kPresetsCtpValHdl,
2697 _, GATT_WRITE, _, _))
2698 .Times(1);
2699
2700 HasClient::Get()->NextActivePreset(not_synced_group);
2701 ASSERT_EQ(group_active_preset_index, 55);
2702 }
2703
TEST_F(HasClientTest,test_select_group_preset_next_preset_sync_supported)2704 TEST_F(HasClientTest, test_select_group_preset_next_preset_sync_supported) {
2705 /* Only one of these devices support preset syncing */
2706 const RawAddress test_address1 = GetTestAddress(1);
2707 uint16_t test_conn_id1 = GetTestConnId(test_address1);
2708 SetSampleDatabaseHasPresetsNtf(
2709 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2710
2711 const RawAddress test_address2 = GetTestAddress(2);
2712 uint16_t test_conn_id2 = GetTestConnId(test_address2);
2713 SetSampleDatabaseHasPresetsNtf(
2714 test_address2,
2715 bluetooth::has::kFeatureBitHearingAidTypeBinaural |
2716 bluetooth::has::kFeatureBitPresetSynchronizationSupported);
2717
2718 uint8_t active_preset_index1 = 0;
2719 uint8_t active_preset_index2 = 0;
2720
2721 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2722 std::variant<RawAddress, int>(test_address1), _))
2723 .WillOnce(SaveArg<1>(&active_preset_index1));
2724 TestConnect(test_address1);
2725
2726 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2727 std::variant<RawAddress, int>(test_address2), _))
2728 .WillOnce(SaveArg<1>(&active_preset_index2));
2729 TestConnect(test_address2);
2730
2731 /* Mock the csis group with two devices */
2732 uint8_t synced_group = 13;
2733 ON_CALL(mock_csis_client_module_, GetDeviceList(synced_group))
2734 .WillByDefault(
2735 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2736 ON_CALL(
2737 mock_csis_client_module_,
2738 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2739 .WillByDefault(Return(synced_group));
2740 ON_CALL(
2741 mock_csis_client_module_,
2742 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2743 .WillByDefault(Return(synced_group));
2744
2745 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2746 _, ErrorCode::GROUP_OPERATION_NOT_SUPPORTED))
2747 .Times(0);
2748
2749 /* Expect callback from the group but not from the devices */
2750 uint8_t group_active_preset_index = 0;
2751 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2752 std::variant<RawAddress, int>(test_address1), _))
2753 .Times(0);
2754 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2755 std::variant<RawAddress, int>(test_address2), _))
2756 .Times(0);
2757 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2758 std::variant<RawAddress, int>(synced_group), _))
2759 .WillOnce(SaveArg<1>(&group_active_preset_index));
2760
2761 /* Expect Ctp write on on this device which forwards operation to the other */
2762 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id1,
2763 HasDbBuilder::kPresetsCtpValHdl,
2764 _, GATT_WRITE, _, _))
2765 .Times(0);
2766 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id2,
2767 HasDbBuilder::kPresetsCtpValHdl,
2768 _, GATT_WRITE, _, _))
2769 .Times(1);
2770
2771 HasClient::Get()->NextActivePreset(synced_group);
2772 ASSERT_EQ(group_active_preset_index, 55);
2773 }
2774
TEST_F(HasClientTest,test_select_preset_prev)2775 TEST_F(HasClientTest, test_select_preset_prev) {
2776 const RawAddress test_address = GetTestAddress(1);
2777
2778 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
2779 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
2780 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
2781 "Preset2"),
2782 }};
2783 SetSampleDatabaseHasPresetsNtf(
2784 test_address,
2785 bluetooth::has::kFeatureBitHearingAidTypeBanded |
2786 bluetooth::has::kFeatureBitWritablePresets |
2787 bluetooth::has::kFeatureBitDynamicPresets,
2788 presets);
2789
2790 uint8_t active_preset_index = 0;
2791 std::vector<PresetInfo> preset_details;
2792
2793 EXPECT_CALL(*callbacks,
2794 OnPresetInfo(std::variant<RawAddress, int>(test_address),
2795 PresetInfoReason::ALL_PRESET_INFO, _))
2796 .Times(1)
2797 .WillOnce(SaveArg<2>(&preset_details));
2798 ON_CALL(*callbacks, OnActivePresetSelected(_, _))
2799 .WillByDefault(SaveArg<1>(&active_preset_index));
2800 TestConnect(test_address);
2801
2802 HasClient::Get()->SelectActivePreset(test_address, 2);
2803 ASSERT_TRUE(preset_details.size() > 1);
2804 ASSERT_EQ(2, active_preset_index);
2805
2806 /* Verify active preset change */
2807 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2808 std::variant<RawAddress, int>(test_address), 1));
2809 HasClient::Get()->PreviousActivePreset(test_address);
2810 }
2811
TEST_F(HasClientTest,test_select_group_preset_prev_no_preset_sync_supported)2812 TEST_F(HasClientTest, test_select_group_preset_prev_no_preset_sync_supported) {
2813 /* None of these devices support preset syncing */
2814 const RawAddress test_address1 = GetTestAddress(1);
2815 SetSampleDatabaseHasPresetsNtf(
2816 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2817
2818 const RawAddress test_address2 = GetTestAddress(2);
2819 SetSampleDatabaseHasPresetsNtf(
2820 test_address2, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2821
2822 TestConnect(test_address1);
2823 TestConnect(test_address2);
2824
2825 /* Mock the csis group with two devices */
2826 uint8_t not_synced_group = 13;
2827 ON_CALL(mock_csis_client_module_, GetDeviceList(not_synced_group))
2828 .WillByDefault(
2829 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2830 ON_CALL(
2831 mock_csis_client_module_,
2832 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2833 .WillByDefault(Return(not_synced_group));
2834 ON_CALL(
2835 mock_csis_client_module_,
2836 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2837 .WillByDefault(Return(not_synced_group));
2838
2839 uint8_t group_active_preset_index = 0;
2840 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2841 std::variant<RawAddress, int>(test_address1), 55))
2842 .Times(0);
2843 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2844 std::variant<RawAddress, int>(test_address2), 55))
2845 .Times(0);
2846 EXPECT_CALL(*callbacks,
2847 OnActivePresetSelected(
2848 std::variant<RawAddress, int>(not_synced_group), _))
2849 .WillOnce(SaveArg<1>(&group_active_preset_index));
2850
2851 /* No locally synced opcodes support so expect both devices getting writes */
2852 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address1),
2853 HasDbBuilder::kPresetsCtpValHdl,
2854 _, GATT_WRITE, _, _))
2855 .Times(1);
2856 EXPECT_CALL(gatt_queue, WriteCharacteristic(GetTestConnId(test_address2),
2857 HasDbBuilder::kPresetsCtpValHdl,
2858 _, GATT_WRITE, _, _))
2859 .Times(1);
2860
2861 HasClient::Get()->PreviousActivePreset(not_synced_group);
2862 ASSERT_EQ(group_active_preset_index, 55);
2863 }
2864
TEST_F(HasClientTest,test_select_group_preset_prev_preset_sync_supported)2865 TEST_F(HasClientTest, test_select_group_preset_prev_preset_sync_supported) {
2866 /* Only one of these devices support preset syncing */
2867 const RawAddress test_address1 = GetTestAddress(1);
2868 uint16_t test_conn_id1 = GetTestConnId(test_address1);
2869 SetSampleDatabaseHasPresetsNtf(
2870 test_address1, bluetooth::has::kFeatureBitHearingAidTypeBinaural);
2871
2872 const RawAddress test_address2 = GetTestAddress(2);
2873 uint16_t test_conn_id2 = GetTestConnId(test_address2);
2874 SetSampleDatabaseHasPresetsNtf(
2875 test_address2,
2876 bluetooth::has::kFeatureBitHearingAidTypeBinaural |
2877 bluetooth::has::kFeatureBitPresetSynchronizationSupported);
2878
2879 uint8_t active_preset_index1 = 0;
2880 uint8_t active_preset_index2 = 0;
2881
2882 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2883 std::variant<RawAddress, int>(test_address1), _))
2884 .WillOnce(SaveArg<1>(&active_preset_index1));
2885 TestConnect(test_address1);
2886
2887 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2888 std::variant<RawAddress, int>(test_address2), _))
2889 .WillOnce(SaveArg<1>(&active_preset_index2));
2890 TestConnect(test_address2);
2891
2892 /* Mock the csis group with two devices */
2893 uint8_t synced_group = 13;
2894 ON_CALL(mock_csis_client_module_, GetDeviceList(synced_group))
2895 .WillByDefault(
2896 Return(std::vector<RawAddress>({{test_address1, test_address2}})));
2897 ON_CALL(
2898 mock_csis_client_module_,
2899 GetGroupId(test_address1, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2900 .WillByDefault(Return(synced_group));
2901 ON_CALL(
2902 mock_csis_client_module_,
2903 GetGroupId(test_address2, ::bluetooth::le_audio::uuid::kCapServiceUuid))
2904 .WillByDefault(Return(synced_group));
2905
2906 EXPECT_CALL(*callbacks, OnActivePresetSelectError(
2907 _, ErrorCode::GROUP_OPERATION_NOT_SUPPORTED))
2908 .Times(0);
2909
2910 /* Expect callback from the group but not from the devices */
2911 uint8_t group_active_preset_index = 0;
2912 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2913 std::variant<RawAddress, int>(test_address1), _))
2914 .Times(0);
2915 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2916 std::variant<RawAddress, int>(test_address2), _))
2917 .Times(0);
2918 EXPECT_CALL(*callbacks, OnActivePresetSelected(
2919 std::variant<RawAddress, int>(synced_group), _))
2920 .WillOnce(SaveArg<1>(&group_active_preset_index));
2921
2922 /* Expect Ctp write on on this device which forwards operation to the other */
2923 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id1,
2924 HasDbBuilder::kPresetsCtpValHdl,
2925 _, GATT_WRITE, _, _))
2926 .Times(0);
2927 EXPECT_CALL(gatt_queue, WriteCharacteristic(test_conn_id2,
2928 HasDbBuilder::kPresetsCtpValHdl,
2929 _, GATT_WRITE, _, _))
2930 .Times(1);
2931
2932 HasClient::Get()->PreviousActivePreset(synced_group);
2933 ASSERT_EQ(group_active_preset_index, 55);
2934 }
2935
TEST_F(HasClientTest,test_select_has_no_presets)2936 TEST_F(HasClientTest, test_select_has_no_presets) {
2937 const RawAddress test_address = GetTestAddress(1);
2938 SetSampleDatabaseHasNoPresetsFlagsOnly(test_address);
2939
2940 EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, _)).Times(1);
2941 EXPECT_CALL(*callbacks,
2942 OnConnectionState(ConnectionState::CONNECTED, test_address))
2943 .Times(1);
2944 TestConnect(test_address);
2945
2946 /* Test this not so useful service */
2947 EXPECT_CALL(*callbacks,
2948 OnActivePresetSelectError(_, ErrorCode::OPERATION_NOT_SUPPORTED))
2949 .Times(3);
2950
2951 HasClient::Get()->SelectActivePreset(test_address, 0x01);
2952 HasClient::Get()->NextActivePreset(test_address);
2953 HasClient::Get()->PreviousActivePreset(test_address);
2954 }
2955
GetSocketBufferSize(int sockfd)2956 static int GetSocketBufferSize(int sockfd) {
2957 int socket_buffer_size;
2958 socklen_t optlen = sizeof(socket_buffer_size);
2959 getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*)&socket_buffer_size,
2960 &optlen);
2961 return socket_buffer_size;
2962 }
2963
SimpleJsonValidator(int fd,int * dumpsys_byte_cnt)2964 bool SimpleJsonValidator(int fd, int* dumpsys_byte_cnt) {
2965 std::ostringstream ss;
2966
2967 char buf{0};
2968 bool within_double_quotes{false};
2969 int left_bracket{0}, right_bracket{0};
2970 int left_sq_bracket{0}, right_sq_bracket{0};
2971 while (read(fd, &buf, 1) != -1) {
2972 switch (buf) {
2973 (*dumpsys_byte_cnt)++;
2974 case '"':
2975 within_double_quotes = !within_double_quotes;
2976 break;
2977 case '{':
2978 if (!within_double_quotes) {
2979 left_bracket++;
2980 }
2981 break;
2982 case '}':
2983 if (!within_double_quotes) {
2984 right_bracket++;
2985 }
2986 break;
2987 case '[':
2988 if (!within_double_quotes) {
2989 left_sq_bracket++;
2990 }
2991 break;
2992 case ']':
2993 if (!within_double_quotes) {
2994 right_sq_bracket++;
2995 }
2996 break;
2997 default:
2998 break;
2999 }
3000 ss << buf;
3001 }
3002 log::error("{}", ss.str());
3003 return (left_bracket == right_bracket) &&
3004 (left_sq_bracket == right_sq_bracket);
3005 }
3006
TEST_F(HasClientTest,test_dumpsys)3007 TEST_F(HasClientTest, test_dumpsys) {
3008 const RawAddress test_address = GetTestAddress(1);
3009
3010 std::set<HasPreset, HasPreset::ComparatorDesc> presets = {{
3011 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
3012 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3013 "Preset2"),
3014 }};
3015 SetSampleDatabaseHasPresetsNtf(
3016 test_address,
3017 bluetooth::has::kFeatureBitHearingAidTypeBanded |
3018 bluetooth::has::kFeatureBitWritablePresets |
3019 bluetooth::has::kFeatureBitDynamicPresets,
3020 presets);
3021
3022 uint8_t active_preset_index = 0;
3023 std::vector<PresetInfo> preset_details;
3024
3025 EXPECT_CALL(*callbacks,
3026 OnPresetInfo(std::variant<RawAddress, int>(test_address),
3027 PresetInfoReason::ALL_PRESET_INFO, _))
3028 .Times(1)
3029 .WillOnce(SaveArg<2>(&preset_details));
3030 ON_CALL(*callbacks, OnActivePresetSelected(_, _))
3031 .WillByDefault(SaveArg<1>(&active_preset_index));
3032 TestConnect(test_address);
3033
3034 int sv[2];
3035 ASSERT_EQ(0, socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, sv));
3036 int socket_buffer_size = GetSocketBufferSize(sv[0]);
3037
3038 HasClient::Get()->DebugDump(sv[0]);
3039 int dumpsys_byte_cnt = 0;
3040 ASSERT_TRUE(dumpsys_byte_cnt < socket_buffer_size);
3041 ASSERT_TRUE(SimpleJsonValidator(sv[1], &dumpsys_byte_cnt));
3042 }
3043
TEST_F(HasClientTest,test_connect_database_out_of_sync)3044 TEST_F(HasClientTest, test_connect_database_out_of_sync) {
3045 osi_property_set_bool("persist.bluetooth.has.always_use_preset_cache", false);
3046
3047 const RawAddress test_address = GetTestAddress(1);
3048 std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
3049 HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
3050 HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3051 "Preset2"),
3052 }};
3053 SetSampleDatabaseHasPresetsNtf(
3054 test_address,
3055 bluetooth::has::kFeatureBitHearingAidTypeBanded |
3056 bluetooth::has::kFeatureBitWritablePresets |
3057 bluetooth::has::kFeatureBitDynamicPresets,
3058 has_presets);
3059
3060 EXPECT_CALL(*callbacks, OnDeviceAvailable(
3061 test_address,
3062 bluetooth::has::kFeatureBitHearingAidTypeBanded |
3063 bluetooth::has::kFeatureBitWritablePresets |
3064 bluetooth::has::kFeatureBitDynamicPresets));
3065 EXPECT_CALL(*callbacks,
3066 OnConnectionState(ConnectionState::CONNECTED, test_address));
3067 TestConnect(test_address);
3068
3069 ON_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _))
3070 .WillByDefault(
3071 Invoke([this](uint16_t conn_id, uint16_t handle,
3072 std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
3073 GATT_WRITE_OP_CB cb, void* cb_data) {
3074 auto* svc = gatt::FindService(services_map[conn_id], handle);
3075 if (svc == nullptr) return;
3076
3077 tGATT_STATUS status = GATT_DATABASE_OUT_OF_SYNC;
3078 if (cb)
3079 cb(conn_id, status, handle, value.size(), value.data(), cb_data);
3080 }));
3081
3082 ON_CALL(gatt_interface, ServiceSearchRequest(_, _)).WillByDefault(Return());
3083 EXPECT_CALL(gatt_interface, ServiceSearchRequest(_, _));
3084 HasClient::Get()->GetPresetInfo(test_address, 1);
3085 }
3086
3087 class HasTypesTest : public ::testing::Test {
3088 protected:
SetUp(void)3089 void SetUp(void) override { reset_mock_function_count_map(); }
3090
TearDown(void)3091 void TearDown(void) override {}
3092 }; // namespace
3093
TEST_F(HasTypesTest,test_has_preset_serialize)3094 TEST_F(HasTypesTest, test_has_preset_serialize) {
3095 HasPreset preset(0x01,
3096 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3097 "My Writable Preset01");
3098
3099 auto sp_sz = preset.SerializedSize();
3100 std::vector<uint8_t> serialized(sp_sz);
3101
3102 ASSERT_EQ(1 + // preset index
3103 1 + // properties
3104 1 + // name length
3105 preset.GetName().length(),
3106 sp_sz);
3107
3108 /* Serialize should move the received buffer pointer by the size of data
3109 */
3110 ASSERT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3111 serialized.data() + serialized.size());
3112
3113 /* Deserialize */
3114 HasPreset clone;
3115 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), serialized.size(), clone),
3116 serialized.data() + serialized.size());
3117
3118 /* Verify */
3119 ASSERT_EQ(preset.GetIndex(), clone.GetIndex());
3120 ASSERT_EQ(preset.GetProperties(), clone.GetProperties());
3121 ASSERT_EQ(preset.GetName(), clone.GetName());
3122 }
3123
TEST_F(HasTypesTest,test_has_preset_serialize_output_buffer_to_small)3124 TEST_F(HasTypesTest, test_has_preset_serialize_output_buffer_to_small) {
3125 HasPreset preset(0x01,
3126 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3127 "My Writable Preset01");
3128
3129 /* On failure, the offset should still point on .data() */
3130 std::vector<uint8_t> serialized(preset.SerializedSize() - 1);
3131 ASSERT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3132 serialized.data());
3133 ASSERT_EQ(preset.Serialize(serialized.data(), 0), serialized.data());
3134 ASSERT_EQ(preset.Serialize(serialized.data(), 1), serialized.data());
3135 ASSERT_EQ(preset.Serialize(serialized.data(), 10), serialized.data());
3136 }
3137
TEST_F(HasTypesTest,test_has_preset_serialize_name_to_long)3138 TEST_F(HasTypesTest, test_has_preset_serialize_name_to_long) {
3139 HasPreset preset(0x01,
3140 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3141 "This name is more than 40 characters long");
3142
3143 /* On failure, the offset should still point on .data() */
3144 std::vector<uint8_t> serialized(preset.SerializedSize());
3145 EXPECT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3146 serialized.data());
3147 }
3148
TEST_F(HasTypesTest,test_has_preset_deserialize_input_buffer_to_small)3149 TEST_F(HasTypesTest, test_has_preset_deserialize_input_buffer_to_small) {
3150 HasPreset preset(0x01,
3151 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3152 "My Writable Preset01");
3153
3154 std::vector<uint8_t> serialized(preset.SerializedSize());
3155
3156 /* Serialize should move the received buffer pointer by the size of data
3157 */
3158 ASSERT_EQ(preset.Serialize(serialized.data(), serialized.size()),
3159 serialized.data() + serialized.size());
3160
3161 /* Deserialize */
3162 HasPreset clone;
3163 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), 0, clone),
3164 serialized.data());
3165 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), 1, clone),
3166 serialized.data());
3167 ASSERT_EQ(HasPreset::Deserialize(serialized.data(), 11, clone),
3168 serialized.data());
3169 ASSERT_EQ(
3170 HasPreset::Deserialize(serialized.data(), serialized.size() - 1, clone),
3171 serialized.data());
3172 }
3173
TEST_F(HasTypesTest,test_has_presets_serialize)3174 TEST_F(HasTypesTest, test_has_presets_serialize) {
3175 HasPreset preset(0x01,
3176 HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
3177 "My Writable Preset01");
3178
3179 HasPreset preset2(0x02, 0, "Nonwritable Unavailable Preset");
3180
3181 HasDevice has_device(GetTestAddress(1));
3182 has_device.has_presets.insert(preset);
3183 has_device.has_presets.insert(preset2);
3184
3185 auto out_buf_sz = has_device.SerializedPresetsSize();
3186 ASSERT_EQ(out_buf_sz, preset.SerializedSize() + preset2.SerializedSize() + 2);
3187
3188 /* Serialize should append to the vector */
3189 std::vector<uint8_t> serialized;
3190 ASSERT_TRUE(has_device.SerializePresets(serialized));
3191 ASSERT_EQ(out_buf_sz, serialized.size());
3192
3193 /* Deserialize */
3194 HasDevice clone(GetTestAddress(1));
3195 ASSERT_TRUE(HasDevice::DeserializePresets(serialized.data(),
3196 serialized.size(), clone));
3197
3198 /* Verify */
3199 ASSERT_EQ(clone.has_presets.size(), has_device.has_presets.size());
3200 ASSERT_NE(0u, clone.has_presets.count(0x01));
3201 ASSERT_NE(0u, clone.has_presets.count(0x02));
3202
3203 ASSERT_EQ(clone.has_presets.find(0x01)->GetIndex(),
3204 has_device.has_presets.find(0x01)->GetIndex());
3205 ASSERT_EQ(clone.has_presets.find(0x01)->GetProperties(),
3206 has_device.has_presets.find(0x01)->GetProperties());
3207 ASSERT_EQ(clone.has_presets.find(0x01)->GetName(),
3208 has_device.has_presets.find(0x01)->GetName());
3209
3210 ASSERT_EQ(clone.has_presets.find(0x02)->GetIndex(),
3211 has_device.has_presets.find(0x02)->GetIndex());
3212 ASSERT_EQ(clone.has_presets.find(0x02)->GetProperties(),
3213 has_device.has_presets.find(0x02)->GetProperties());
3214 ASSERT_EQ(clone.has_presets.find(0x02)->GetName(),
3215 has_device.has_presets.find(0x02)->GetName());
3216 }
3217
TEST_F(HasTypesTest,test_group_op_coordinator_init)3218 TEST_F(HasTypesTest, test_group_op_coordinator_init) {
3219 HasCtpGroupOpCoordinator::Initialize([](void*) {
3220 /* Do nothing */
3221 });
3222 ASSERT_EQ(0u, HasCtpGroupOpCoordinator::ref_cnt);
3223 auto address1 = GetTestAddress(1);
3224 auto address2 = GetTestAddress(2);
3225
3226 HasCtpGroupOpCoordinator wrapper(
3227 {address1, address2},
3228 HasCtpOp(0x01, ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESETS,
3229 6));
3230 ASSERT_EQ(2u, wrapper.ref_cnt);
3231
3232 HasCtpGroupOpCoordinator::Cleanup();
3233 ASSERT_EQ(0u, wrapper.ref_cnt);
3234
3235 ASSERT_EQ(1, get_func_call_count("alarm_free"));
3236 ASSERT_EQ(1, get_func_call_count("alarm_new"));
3237 }
3238
TEST_F(HasTypesTest,test_group_op_coordinator_copy)3239 TEST_F(HasTypesTest, test_group_op_coordinator_copy) {
3240 HasCtpGroupOpCoordinator::Initialize([](void*) {
3241 /* Do nothing */
3242 });
3243 ASSERT_EQ(0u, HasCtpGroupOpCoordinator::ref_cnt);
3244 auto address1 = GetTestAddress(1);
3245 auto address2 = GetTestAddress(2);
3246
3247 HasCtpGroupOpCoordinator wrapper(
3248 {address1, address2},
3249 HasCtpOp(0x01, ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESETS,
3250 6));
3251 HasCtpGroupOpCoordinator wrapper2(
3252 {address1},
3253 HasCtpOp(0x01, ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESETS,
3254 6));
3255 ASSERT_EQ(3u, wrapper.ref_cnt);
3256 HasCtpGroupOpCoordinator wrapper3 = wrapper2;
3257 auto* wrapper4 =
3258 new HasCtpGroupOpCoordinator(HasCtpGroupOpCoordinator(wrapper2));
3259 ASSERT_EQ(5u, wrapper.ref_cnt);
3260
3261 delete wrapper4;
3262 ASSERT_EQ(4u, wrapper.ref_cnt);
3263
3264 HasCtpGroupOpCoordinator::Cleanup();
3265 ASSERT_EQ(0u, wrapper.ref_cnt);
3266
3267 ASSERT_EQ(1, get_func_call_count("alarm_free"));
3268 ASSERT_EQ(1, get_func_call_count("alarm_new"));
3269 }
3270
TEST_F(HasTypesTest,test_group_op_coordinator_completion)3271 TEST_F(HasTypesTest, test_group_op_coordinator_completion) {
3272 HasCtpGroupOpCoordinator::Initialize([](void*) {
3273 /* Do nothing */
3274 log::info("callback call");
3275 });
3276 ASSERT_EQ(0u, HasCtpGroupOpCoordinator::ref_cnt);
3277 auto address1 = GetTestAddress(1);
3278 auto address2 = GetTestAddress(2);
3279 auto address3 = GetTestAddress(3);
3280
3281 HasCtpGroupOpCoordinator wrapper(
3282 {address1, address3},
3283 HasCtpOp(0x01, ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESETS,
3284 6));
3285 HasCtpGroupOpCoordinator wrapper2(
3286 {address2},
3287 HasCtpOp(0x01, ::bluetooth::le_audio::has::PresetCtpOpcode::READ_PRESETS,
3288 6));
3289 ASSERT_EQ(3u, wrapper.ref_cnt);
3290
3291 ASSERT_FALSE(wrapper.IsFullyCompleted());
3292
3293 wrapper.SetCompleted(address1);
3294 ASSERT_EQ(2u, wrapper.ref_cnt);
3295
3296 wrapper.SetCompleted(address3);
3297 ASSERT_EQ(1u, wrapper.ref_cnt);
3298 ASSERT_FALSE(wrapper.IsFullyCompleted());
3299 ASSERT_EQ(0, get_func_call_count("alarm_free"));
3300
3301 /* Non existing address completion */
3302 wrapper.SetCompleted(address2);
3303 ASSERT_EQ(0, get_func_call_count("alarm_free"));
3304 ASSERT_EQ(1u, wrapper.ref_cnt);
3305
3306 /* Last device address completion */
3307 wrapper2.SetCompleted(address2);
3308 ASSERT_TRUE(wrapper.IsFullyCompleted());
3309 ASSERT_EQ(0u, wrapper.ref_cnt);
3310 const int alarm_free_count = get_func_call_count("alarm_free");
3311 ASSERT_EQ(1, alarm_free_count);
3312
3313 HasCtpGroupOpCoordinator::Cleanup();
3314
3315 ASSERT_EQ(alarm_free_count, get_func_call_count("alarm_free"));
3316 ASSERT_EQ(1, get_func_call_count("alarm_new"));
3317 }
3318
3319 } // namespace
3320 } // namespace internal
3321 } // namespace has
3322 } // namespace bluetooth
3323