| // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "bluetooth/newblued/util.h" |
| |
| #include <cstdint> |
| #include <string> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <newblue/gatt.h> |
| #include <newblue/uuid.h> |
| |
| #include "bluetooth/newblued/uuid.h" |
| |
| namespace { |
| |
| constexpr char device_object_prefix[] = "/org/bluez/hci0/dev_"; |
| |
| const char* const kInvalidAddresses[] = { |
| "", |
| "11", |
| "11:1:11:11:11:11", |
| "11:11:11:11:11:11:", |
| "11:11:11:1G:11:11", |
| "11:11:11:11:11:11:11", |
| }; |
| |
| const char* const kInvalidDeviceObjectPathes[] = { |
| "", |
| "11", |
| "11_1_11_11_11_11", |
| "11_11_11_11_11_11_", |
| "11_11_11_1G_11_11", |
| "11_11_11_11_11_11_11", |
| }; |
| |
| } // namespace |
| |
| namespace bluetooth { |
| |
| using ::testing::ElementsAre; |
| using ::testing::Pair; |
| using ::testing::UnorderedElementsAre; |
| |
| TEST(UtilTest, GetFromLE) { |
| uint8_t le16[] = {0x11, 0x22}; |
| uint8_t le24[] = {0x33, 0x44, 0x55}; |
| uint8_t le_bytes[] = {0x11, 0x22, 0x33, 0x44, 0x55}; |
| std::vector<uint8_t> expected_bytes({0x55, 0x44, 0x33, 0x22, 0x11}); |
| |
| EXPECT_EQ(0x2211, GetNumFromLE16(le16)); |
| EXPECT_EQ(0x554433, GetNumFromLE24(le24)); |
| EXPECT_EQ(expected_bytes, GetBytesFromLE(le_bytes, sizeof(le_bytes))); |
| |
| EXPECT_TRUE(GetBytesFromLE(le_bytes, 0).empty()); |
| } |
| |
| TEST(UtilTest, GetNextId) { |
| UniqueId id1 = GetNextId(); |
| UniqueId id2 = GetNextId(); |
| |
| EXPECT_NE(kInvalidUniqueId, id1); |
| EXPECT_NE(kInvalidUniqueId, id2); |
| EXPECT_NE(id1, id2); |
| EXPECT_LT(id1, id2); |
| } |
| |
| TEST(UtilTest, ConvertToBtAddr) { |
| for (const char* address : kInvalidAddresses) { |
| struct bt_addr result {}; |
| EXPECT_FALSE(ConvertToBtAddr(false, address, &result)); |
| EXPECT_EQ(result.type, 0); |
| EXPECT_THAT(result.addr, ElementsAre(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| } |
| { |
| struct bt_addr result {}; |
| EXPECT_TRUE(ConvertToBtAddr(false, "12:34:56:78:9A:BC", &result)); |
| EXPECT_EQ(result.type, BT_ADDR_TYPE_LE_PUBLIC); |
| EXPECT_THAT(result.addr, ElementsAre(0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12)); |
| } |
| { |
| struct bt_addr result {}; |
| EXPECT_TRUE(ConvertToBtAddr(true, "CB:A9:87:65:43:21", &result)); |
| EXPECT_EQ(result.type, BT_ADDR_TYPE_LE_RANDOM); |
| EXPECT_THAT(result.addr, ElementsAre(0x21, 0x43, 0x65, 0x87, 0xA9, 0xCB)); |
| } |
| } |
| |
| TEST(UtilTest, TrimAdapterFromObjectPath) { |
| std::string path("org/bluez"); |
| std::string path2("/org/bluez/hcix"); |
| std::string path3("/org/bluez/hci0/dev_12_34_56_78_9A_BC"); |
| std::string path4("/org/bluez/hci10"); |
| |
| EXPECT_FALSE(TrimAdapterFromObjectPath(&path)); |
| EXPECT_EQ("org/bluez", path); |
| EXPECT_FALSE(TrimAdapterFromObjectPath(&path2)); |
| EXPECT_EQ("/org/bluez/hcix", path2); |
| EXPECT_FALSE(TrimAdapterFromObjectPath(&path3)); |
| EXPECT_EQ("/org/bluez/hci0/dev_12_34_56_78_9A_BC", path3); |
| EXPECT_TRUE(TrimAdapterFromObjectPath(&path4)); |
| EXPECT_TRUE(path4.empty()); |
| } |
| |
| TEST(UtilTest, TrimDeviceFromObjectPath) { |
| std::string path("dev_12_34_56_78_9A_BC"); |
| std::string path2("/dev_12_34_56"); |
| std::string path3("/dev_12_34_56_78_9A_BC"); |
| std::string path4("/org/bluez/hci0/dev_12_34_56_78_9a_bc"); |
| |
| EXPECT_EQ("", TrimDeviceFromObjectPath(&path)); |
| EXPECT_EQ("dev_12_34_56_78_9A_BC", path); |
| EXPECT_EQ("", TrimDeviceFromObjectPath(&path2)); |
| EXPECT_EQ("/dev_12_34_56", path2); |
| EXPECT_EQ("12:34:56:78:9A:BC", TrimDeviceFromObjectPath(&path3)); |
| EXPECT_EQ("", path3); |
| EXPECT_EQ("12:34:56:78:9a:bc", TrimDeviceFromObjectPath(&path4)); |
| EXPECT_EQ("/org/bluez/hci0", path4); |
| } |
| |
| TEST(UtilTest, TrimServiceFromObjectPath) { |
| std::string path("service01"); |
| std::string path2("/service1FF"); |
| std::string path3("/service001F"); |
| std::string path4("/dev_12_34_56_78_9A_BC/service001F"); |
| |
| EXPECT_EQ(kInvalidServiceHandle, TrimServiceFromObjectPath(&path)); |
| EXPECT_EQ("service01", path); |
| EXPECT_EQ(kInvalidServiceHandle, TrimServiceFromObjectPath(&path2)); |
| EXPECT_EQ("/service1FF", path2); |
| EXPECT_EQ(0x001F, TrimServiceFromObjectPath(&path3)); |
| EXPECT_TRUE(path3.empty()); |
| EXPECT_EQ(0x001F, TrimServiceFromObjectPath(&path4)); |
| EXPECT_EQ("/dev_12_34_56_78_9A_BC", path4); |
| } |
| |
| TEST(UtilTest, TrimCharacteristicFromObjectPath) { |
| std::string path("char0123"); |
| std::string path2("/charxxxx"); |
| std::string path3("/char01FFF"); |
| std::string path4("/char01ff"); |
| std::string path5("/service01FF/char01FF"); |
| |
| EXPECT_EQ(kInvalidCharacteristicHandle, |
| TrimCharacteristicFromObjectPath(&path)); |
| EXPECT_EQ("char0123", path); |
| EXPECT_EQ(kInvalidCharacteristicHandle, |
| TrimCharacteristicFromObjectPath(&path2)); |
| EXPECT_EQ("/charxxxx", path2); |
| EXPECT_EQ(kInvalidCharacteristicHandle, |
| TrimCharacteristicFromObjectPath(&path3)); |
| EXPECT_EQ("/char01FFF", path3); |
| EXPECT_EQ(0x01FF, TrimCharacteristicFromObjectPath(&path4)); |
| EXPECT_TRUE(path4.empty()); |
| EXPECT_EQ(0x01FF, TrimCharacteristicFromObjectPath(&path5)); |
| EXPECT_EQ("/service01FF", path5); |
| } |
| |
| TEST(UtilTest, TrimDescriptorFromObjectPath) { |
| std::string path("desc01F"); |
| std::string path2("/desc01F"); |
| std::string path3("/desc01ff"); |
| std::string path4("/char0123/desc01FF"); |
| |
| EXPECT_EQ(kInvalidDescriptorHandle, TrimDescriptorFromObjectPath(&path)); |
| EXPECT_EQ("desc01F", path); |
| EXPECT_EQ(kInvalidDescriptorHandle, TrimDescriptorFromObjectPath(&path2)); |
| EXPECT_EQ("/desc01F", path2); |
| EXPECT_EQ(0x01FF, TrimDescriptorFromObjectPath(&path3)); |
| EXPECT_TRUE(path3.empty()); |
| EXPECT_EQ(0x01FF, TrimDescriptorFromObjectPath(&path4)); |
| EXPECT_EQ("/char0123", path4); |
| } |
| |
| TEST(UtilTest, ConvertToObjectPath) { |
| std::string address("11:22:33:44:55:66"); |
| std::string dev_p = std::string(device_object_prefix) + "11_22_33_44_55_66"; |
| uint16_t sh = 0x01FF; |
| std::string sp("/service01FF"); |
| uint16_t ch = 0x01FF; |
| std::string cp("/char01FF"); |
| uint16_t dh = 0x01FF; |
| std::string dp("/desc01FF"); |
| |
| // device |
| EXPECT_TRUE(ConvertDeviceAddressToObjectPath("").value().empty()); |
| EXPECT_EQ(dev_p, ConvertDeviceAddressToObjectPath(address).value()); |
| |
| // service |
| EXPECT_EQ(dev_p + sp, ConvertServiceHandleToObjectPath(address, sh).value()); |
| |
| // characteristic |
| EXPECT_EQ(dev_p + sp + cp, |
| ConvertCharacteristicHandleToObjectPath(address, sh, ch).value()); |
| |
| // descriptor |
| EXPECT_EQ(dev_p + sp + cp + dp, |
| ConvertDescriptorHandleToObjectPath(address, sh, ch, dh).value()); |
| } |
| |
| TEST(UtilTest, ConvertDeviceObjectPathToAddress) { |
| const std::string prefix = device_object_prefix; |
| for (const char* address : kInvalidDeviceObjectPathes) { |
| EXPECT_EQ("", ConvertDeviceObjectPathToAddress(address)); |
| EXPECT_EQ("", ConvertDeviceObjectPathToAddress(prefix + address)); |
| } |
| EXPECT_EQ("", ConvertDeviceObjectPathToAddress("12_34_56_78_9A_BC")); |
| EXPECT_EQ("12:34:56:78:9A:BC", |
| ConvertDeviceObjectPathToAddress(prefix + "12_34_56_78_9A_BC")); |
| EXPECT_EQ("12:34:56:78:9a:bc", |
| ConvertDeviceObjectPathToAddress(prefix + "12_34_56_78_9a_bc")); |
| } |
| |
| TEST(UtilTest, ConvertServiceObjectPathToHandle) { |
| std::string path("/org/bluez"); |
| std::string path2( |
| "/org/bluez/hci0/dev_00_01_02_03_04_05/service001F/char0123"); |
| std::string path3("/org/bluez/hci0/dev_00_01_02_03_04_05/service001F"); |
| |
| std::string address(""); |
| uint16_t h = 0x0000; |
| |
| EXPECT_FALSE(ConvertServiceObjectPathToHandle(&address, &h, path)); |
| EXPECT_TRUE(address.empty()); |
| EXPECT_EQ(0x0000, h); |
| |
| EXPECT_FALSE(ConvertServiceObjectPathToHandle(&address, &h, path2)); |
| EXPECT_TRUE(address.empty()); |
| EXPECT_EQ(0x0000, h); |
| |
| EXPECT_TRUE(ConvertServiceObjectPathToHandle(&address, &h, path3)); |
| EXPECT_EQ("00:01:02:03:04:05", address); |
| EXPECT_EQ(0x001F, h); |
| } |
| |
| TEST(UtilTest, ConvertCharacteristicObjectPathToHandles) { |
| std::string path("/org/bluez"); |
| std::string path2( |
| "/org/bluez/hci0/dev_00_01_02_03_04_05/service001F/char0123/" |
| "desc01FF"); |
| std::string path3( |
| "/org/bluez/hci0/dev_00_01_02_03_04_05/service001F/char0123"); |
| |
| std::string address(""); |
| uint16_t sh = 0x0000; |
| uint16_t ch = 0x0000; |
| |
| EXPECT_FALSE( |
| ConvertCharacteristicObjectPathToHandles(&address, &sh, &ch, path)); |
| EXPECT_TRUE(address.empty()); |
| EXPECT_EQ(0x0000, sh); |
| EXPECT_EQ(0x0000, ch); |
| |
| EXPECT_FALSE( |
| ConvertCharacteristicObjectPathToHandles(&address, &sh, &ch, path2)); |
| EXPECT_TRUE(address.empty()); |
| EXPECT_EQ(0x0000, sh); |
| EXPECT_EQ(0x0000, ch); |
| |
| EXPECT_TRUE( |
| ConvertCharacteristicObjectPathToHandles(&address, &sh, &ch, path3)); |
| EXPECT_EQ("00:01:02:03:04:05", address); |
| EXPECT_EQ(0x001F, sh); |
| EXPECT_EQ(0x0123, ch); |
| } |
| |
| TEST(UtilTest, ConvertDescriptorObjectPathToHandles) { |
| std::string path("/org/bluez"); |
| std::string path2( |
| "/org/bluez/hci0/dev_00_01_02_03_04_05/service001F/char0123/" |
| "desc001F"); |
| |
| std::string address(""); |
| uint16_t sh = 0x0000; |
| uint16_t ch = 0x0000; |
| uint16_t dh = 0x0000; |
| |
| EXPECT_FALSE( |
| ConvertDescriptorObjectPathToHandles(&address, &sh, &ch, &dh, path)); |
| EXPECT_TRUE(address.empty()); |
| EXPECT_EQ(0x0000, sh); |
| EXPECT_EQ(0x0000, ch); |
| EXPECT_EQ(0x0000, dh); |
| |
| EXPECT_TRUE( |
| ConvertDescriptorObjectPathToHandles(&address, &sh, &ch, &dh, path2)); |
| EXPECT_EQ("00:01:02:03:04:05", address); |
| EXPECT_EQ(0x001F, sh); |
| EXPECT_EQ(0x0123, ch); |
| EXPECT_EQ(0x001F, dh); |
| } |
| |
| TEST(UtilTest, ConvertToUuid) { |
| struct uuid uuid; |
| const std::array<uint8_t, 16> expected_value = { |
| 0x00, 0x00, 0x12, 0x34, 0x00, 0x00, 0x10, 0x00, |
| 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, |
| }; |
| const std::string expected_canonical_value( |
| "00001234-0000-1000-8000-00805f9b34fb"); |
| |
| uuidFromUuid16(&uuid, 0x1234); |
| |
| Uuid result = ConvertToUuid(uuid); |
| EXPECT_EQ(UuidFormat::UUID128, result.format()); |
| EXPECT_EQ(expected_value, result.value()); |
| EXPECT_EQ(expected_canonical_value, result.canonical_value()); |
| } |
| |
| TEST(UtilTest, ConvertToRawUuid) { |
| Uuid uuid_invalid; |
| Uuid uuid_16(std::vector<uint8_t>({0x1a, 0x2b})); |
| Uuid uuid_32(std::vector<uint8_t>({0x00, 0x00, 0x1a, 0x2b})); |
| Uuid uuid_128( |
| std::vector<uint8_t>({0x00, 0x00, 0x1a, 0x2b, 0x00, 0x00, 0x10, 0x00, |
| 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb})); |
| |
| struct uuid u_invalid = ConvertToRawUuid(uuid_invalid); |
| struct uuid u_16 = ConvertToRawUuid(uuid_16); |
| struct uuid u_32 = ConvertToRawUuid(uuid_32); |
| struct uuid u_128 = ConvertToRawUuid(uuid_128); |
| |
| EXPECT_TRUE(uuidIsZero(&u_invalid)); |
| EXPECT_EQ(0x00001a2b00001000, u_16.hi); |
| EXPECT_EQ(0x800000805f9b34fb, u_16.lo); |
| EXPECT_TRUE(uuidCmp(&u_16, &u_32)); |
| EXPECT_TRUE(uuidCmp(&u_16, &u_128)); |
| } |
| |
| TEST(UtilTest, ConvertToGattService) { |
| // Service handles and UUID. |
| uint16_t sfh = 0x0001; |
| uint16_t slh = 0x0003; |
| uint16_t suv = 0x1800; |
| Uuid service_uuid(std::vector<uint8_t>({0x18, 0x00})); |
| |
| // Included service handles and UUID. |
| uint16_t isfh = 0x0009; |
| uint16_t islh = 0x000C; |
| uint16_t isih = 0x000A; |
| uint16_t isuv = 0x1801; |
| Uuid included_service_uuid(std::vector<uint8_t>({0x18, 0x01})); |
| |
| // Characteristic handles, property and UUID. |
| uint16_t cfh = 0x0004; |
| uint16_t clh = 0x0006; |
| uint16_t cvh = 0x0005; |
| uint16_t cuv = 0x1802; |
| uint8_t cp = 0xAB; |
| Uuid characteristic_uuid(std::vector<uint8_t>({0x18, 0x02})); |
| |
| // Descriptor handles and UUIDs. |
| uint16_t dh = 0x0007; |
| uint16_t dh2 = 0x0008; |
| uint16_t duv = 0x1803; |
| uint16_t duv2 = 0x1804; |
| Uuid descriptor_uuid(std::vector<uint8_t>({0x18, 0x03})); |
| Uuid descriptor_uuid2(std::vector<uint8_t>({0x18, 0x04})); |
| |
| // Construct struct GattTraversedService. |
| struct GattTraversedServiceCharDescr descriptors[2]; |
| descriptors[0].handle = dh; |
| uuidFromUuid16(&descriptors[0].uuid, duv); |
| descriptors[1].handle = dh2; |
| uuidFromUuid16(&descriptors[1].uuid, duv2); |
| |
| struct GattTraversedServiceChar characteristic; |
| uuidFromUuid16(&characteristic.uuid, cuv); |
| characteristic.charProps = cp; |
| characteristic.valHandle = cvh; |
| characteristic.firstHandle = cfh; |
| characteristic.lastHandle = clh; |
| characteristic.numDescrs = 2; |
| characteristic.descrs = descriptors; |
| |
| struct GattTraversedServiceInclSvc included_service; |
| uuidFromUuid16(&included_service.uuid, isuv); |
| included_service.includeDefHandle = isih; |
| included_service.firstHandle = isfh; |
| included_service.lastHandle = islh; |
| |
| struct GattTraversedService service; |
| uuidFromUuid16(&service.uuid, suv); |
| service.firstHandle = sfh; |
| service.lastHandle = slh; |
| service.numChars = 1; |
| service.chars = &characteristic; |
| service.numInclSvcs = 1; |
| service.inclSvcs = &included_service; |
| |
| // Perform the conversion. |
| std::unique_ptr<GattService> s = ConvertToGattService(service); |
| |
| // Verify service content. |
| EXPECT_NE(nullptr, s); |
| EXPECT_FALSE(s->HasOwner()); |
| EXPECT_TRUE(s->device_address().value().empty()); |
| EXPECT_EQ(sfh, s->first_handle()); |
| EXPECT_EQ(slh, s->last_handle()); |
| EXPECT_TRUE(s->primary().value()); |
| EXPECT_EQ(service_uuid, s->uuid().value()); |
| |
| // Verify included service content. |
| EXPECT_EQ(1, s->included_services().size()); |
| EXPECT_EQ(s.get(), s->included_services().at(isfh)->service()); |
| EXPECT_EQ(isih, s->included_services().at(isfh)->included_handle()); |
| EXPECT_EQ(isfh, s->included_services().at(isfh)->first_handle()); |
| EXPECT_EQ(islh, s->included_services().at(isfh)->last_handle()); |
| EXPECT_EQ(included_service_uuid, s->included_services().at(isfh)->uuid()); |
| |
| // Verify characteristic content. |
| EXPECT_EQ(1, s->characteristics().size()); |
| EXPECT_EQ(s.get(), s->characteristics().at(cfh)->service().value()); |
| EXPECT_EQ(cvh, s->characteristics().at(cfh)->value_handle()); |
| EXPECT_EQ(cfh, s->characteristics().at(cfh)->first_handle()); |
| EXPECT_EQ(clh, s->characteristics().at(cfh)->last_handle()); |
| EXPECT_EQ(cp, s->characteristics().at(cfh)->properties().value()); |
| EXPECT_EQ(characteristic_uuid, s->characteristics().at(cfh)->uuid().value()); |
| EXPECT_TRUE(s->characteristics().at(cfh)->value().value().empty()); |
| EXPECT_EQ(GattCharacteristic::NotifySetting::NONE, |
| s->characteristics().at(cfh)->notify_setting().value()); |
| |
| // Verify descriptors content. |
| EXPECT_EQ(2, s->characteristics().at(cfh)->descriptors().size()); |
| EXPECT_EQ(s->characteristics().at(cfh).get(), s->characteristics() |
| .at(cfh) |
| ->descriptors() |
| .at(dh) |
| ->characteristic() |
| .value()); |
| EXPECT_EQ(dh, s->characteristics().at(cfh)->descriptors().at(dh)->handle()); |
| EXPECT_EQ(descriptor_uuid, |
| s->characteristics().at(cfh)->descriptors().at(dh)->uuid().value()); |
| EXPECT_EQ(s->characteristics().at(cfh).get(), s->characteristics() |
| .at(cfh) |
| ->descriptors() |
| .at(dh2) |
| ->characteristic() |
| .value()); |
| EXPECT_EQ(dh2, s->characteristics().at(cfh)->descriptors().at(dh2)->handle()); |
| EXPECT_EQ( |
| descriptor_uuid2, |
| s->characteristics().at(cfh)->descriptors().at(dh2)->uuid().value()); |
| } |
| |
| TEST(UtilTest, GetBytesFromSg) { |
| std::vector<uint8_t> value({0x11, 0x22, 0x33, 0x44}); |
| std::vector<uint8_t> extracted_value; |
| sg data_null = nullptr; |
| sg data_empty = sgNew(); |
| sg data = sgNewWithCopyData(static_cast<void*>(value.data()), value.size()); |
| |
| extracted_value = GetBytesFromSg(data_null); |
| EXPECT_TRUE(extracted_value.empty()); |
| |
| extracted_value = GetBytesFromSg(data_empty); |
| EXPECT_TRUE(extracted_value.empty()); |
| |
| extracted_value = GetBytesFromSg(data); |
| EXPECT_EQ(value, extracted_value); |
| |
| sgFree(data_empty); |
| sgFree(data); |
| } |
| |
| TEST(UtilTest, ParseEirNormal) { |
| DeviceInfo device_info(/* has_active_discovery_client */ true, |
| /* adv_address */ "", /* address_type */ 0, |
| /* resolved_address */ "", /* rssi */ 0, |
| /* reply_type */ 0); |
| uint8_t eir[] = { |
| // Flag |
| 3, static_cast<uint8_t>(EirType::FLAGS), 0xAA, 0xBB, |
| // UUID16_COMPLETE - Battery Service |
| 3, static_cast<uint8_t>(EirType::UUID16_COMPLETE), 0x0F, 0x18, |
| // UUID32_INCOMPLETE - Blood Pressure |
| 5, static_cast<uint8_t>(EirType::UUID32_INCOMPLETE), 0x10, 0x18, 0x00, |
| 0x00, |
| // UUID128_COMPLETE |
| 17, static_cast<uint8_t>(EirType::UUID128_COMPLETE), 0x0F, 0x0E, 0x0D, |
| 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, |
| 0x00, |
| // Name |
| 4, static_cast<uint8_t>(EirType::NAME_SHORT), 'f', 'o', 'o', |
| // TX Power |
| 2, static_cast<uint8_t>(EirType::TX_POWER), 0xC7, |
| // Class |
| 4, static_cast<uint8_t>(EirType::CLASS_OF_DEV), 0x01, 0x02, 0x03, |
| // Service data associated with 16-bit Battery Service UUID |
| 5, static_cast<uint8_t>(EirType::SVC_DATA16), 0x0F, 0x18, 0x22, 0x11, |
| // Service data associate with 32-bit Bond Management Service UUID |
| 7, static_cast<uint8_t>(EirType::SVC_DATA32), 0x1E, 0x18, 0x00, 0x00, |
| 0x44, 0x33, |
| // Appearance |
| 3, static_cast<uint8_t>(EirType::GAP_APPEARANCE), 0x01, 0x02, |
| // Manufacturer data |
| 5, static_cast<uint8_t>(EirType::MANUFACTURER_DATA), 0x0E, 0x00, 0x55, |
| 0x66}; |
| Uuid battery_service_uuid16(std::vector<uint8_t>({0x18, 0x0F})); |
| Uuid blood_pressure_uuid32(std::vector<uint8_t>({0x00, 0x00, 0x18, 0x10})); |
| Uuid bond_management_service_uuid32( |
| std::vector<uint8_t>({0x00, 0x00, 0x18, 0x1E})); |
| Uuid uuid128( |
| std::vector<uint8_t>({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F})); |
| |
| ParseEir(&device_info, std::vector<uint8_t>(eir, eir + arraysize(eir))); |
| |
| EXPECT_EQ(std::vector<uint8_t>({0xAA}), device_info.flags); |
| EXPECT_THAT(device_info.service_uuids, |
| UnorderedElementsAre(battery_service_uuid16, |
| blood_pressure_uuid32, uuid128)); |
| EXPECT_EQ(std::string("foo") + kNewblueNameSuffix, device_info.name); |
| EXPECT_EQ(-57, device_info.tx_power); |
| EXPECT_EQ(0x00030201, device_info.eir_class); |
| EXPECT_THAT(device_info.service_data, |
| UnorderedElementsAre(Pair(battery_service_uuid16, |
| std::vector<uint8_t>({0x11, 0x22})), |
| Pair(bond_management_service_uuid32, |
| std::vector<uint8_t>({0x33, 0x44})))); |
| EXPECT_EQ(0x0201, device_info.appearance); |
| EXPECT_THAT( |
| device_info.manufacturer, |
| UnorderedElementsAre(Pair(0x000E, std::vector<uint8_t>({0x55, 0x66})))); |
| |
| uint8_t eir2[] = { |
| // Flag with zero octet |
| 1, static_cast<uint8_t>(EirType::FLAGS), |
| // UUID32_INCOMPLETE - Bond Management Service |
| 5, static_cast<uint8_t>(EirType::UUID32_INCOMPLETE), 0x1E, 0x18, 0x00, |
| 0x00, |
| // Service data associate with 32-bit Bond Management Service UUID |
| 7, static_cast<uint8_t>(EirType::SVC_DATA32), 0x1E, 0x18, 0x00, 0x00, |
| 0x66, 0x55}; |
| |
| ParseEir(&device_info, std::vector<uint8_t>(eir2, eir2 + arraysize(eir2))); |
| |
| EXPECT_FALSE(device_info.flags.empty()); |
| EXPECT_THAT(device_info.service_uuids, |
| UnorderedElementsAre(bond_management_service_uuid32)); |
| EXPECT_EQ(std::string("foo") + kNewblueNameSuffix, device_info.name); |
| EXPECT_EQ(-57, device_info.tx_power); |
| EXPECT_EQ(0x00030201, device_info.eir_class); |
| EXPECT_THAT(device_info.service_data, |
| UnorderedElementsAre(Pair(bond_management_service_uuid32, |
| std::vector<uint8_t>({0x55, 0x66})))); |
| EXPECT_EQ(0x0201, device_info.appearance); |
| EXPECT_THAT( |
| device_info.manufacturer, |
| UnorderedElementsAre(Pair(0x000E, std::vector<uint8_t>({0x55, 0x66})))); |
| } |
| |
| TEST(UtilTest, ParseEirAbnormal) { |
| DeviceInfo device_info(/* has_active_discovery_client */ true, |
| /* adv_address */ "", /* address_type */ 0, |
| /* resolved_address */ "", /* rssi */ 0, |
| /* reply_type */ 0); |
| uint8_t eir[] = { |
| // Even if there are more than one instance of a UUID size of either |
| // COMPLETE or INCOMPLETE type, the later one will still be honored |
| 3, static_cast<uint8_t>(EirType::UUID16_COMPLETE), 0x0F, 0x18, // |
| 3, static_cast<uint8_t>(EirType::UUID16_INCOMPLETE), 0x10, 0x18, |
| // Invalid UUID will be dropped. |
| 2, static_cast<uint8_t>(EirType::UUID32_INCOMPLETE), 0x10, |
| // Contains non-ascii character |
| 5, static_cast<uint8_t>(EirType::NAME_SHORT), 0x80, 0x81, 'a', '\0', |
| // TX Power with more than one octet will be dropped |
| 3, static_cast<uint8_t>(EirType::TX_POWER), 0xC7, 0x00, |
| // Class with a wrong field length (2, should be 3) |
| 3, static_cast<uint8_t>(EirType::CLASS_OF_DEV), 0x01, 0x02, |
| // Service data with an invalid service UUID will be dropped |
| 3, static_cast<uint8_t>(EirType::SVC_DATA16), 0x0F, 0x18, |
| // Service data with zero length associated with 16-bit Battery Service |
| // will be dropped |
| 3, static_cast<uint8_t>(EirType::SVC_DATA16), 0x0F, 0x18, |
| // Wrong field length (4, should be 3) |
| 4, static_cast<uint8_t>(EirType::GAP_APPEARANCE), 0x01, 0x02, 0x03}; |
| Uuid battery_service_uuid16(std::vector<uint8_t>({0x18, 0x0F})); |
| Uuid blood_pressure_uuid16(std::vector<uint8_t>({0x18, 0x10})); |
| |
| ParseEir(&device_info, std::vector<uint8_t>(eir, eir + arraysize(eir))); |
| |
| // Non-ascii characters are replaced with spaces. |
| EXPECT_FALSE(device_info.flags.empty()); |
| EXPECT_THAT( |
| device_info.service_uuids, |
| UnorderedElementsAre(battery_service_uuid16, blood_pressure_uuid16)); |
| EXPECT_EQ(std::string(" a") + kNewblueNameSuffix, device_info.name); |
| EXPECT_EQ(-128, device_info.tx_power); |
| EXPECT_EQ(0x1F00, device_info.eir_class); |
| EXPECT_TRUE(device_info.service_data.empty()); |
| EXPECT_EQ(0x0000, device_info.appearance); |
| EXPECT_THAT(device_info.manufacturer, |
| UnorderedElementsAre(Pair(0xFFFF, std::vector<uint8_t>()))); |
| } |
| |
| } // namespace bluetooth |