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