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