blob: d0f2a52858191c2c6e50581a7c029bab1faf95c3 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "garnet/drivers/bluetooth/lib/sdp/data_element.h"
#include "garnet/drivers/bluetooth/lib/sdp/sdp.h"
#include "gtest/gtest.h"
#include "garnet/drivers/bluetooth/lib/common/byte_buffer.h"
#include "garnet/drivers/bluetooth/lib/common/test_helpers.h"
namespace btlib {
namespace sdp {
namespace {
using common::LowerBits;
using common::UpperBits;
using SDP_DataElementTest = ::testing::Test;
TEST_F(SDP_DataElementTest, CreateIsNull) {
DataElement elem;
EXPECT_EQ(DataElement::Type::kNull, elem.type());
EXPECT_TRUE(elem.Get<std::nullptr_t>());
EXPECT_EQ(nullptr, *elem.Get<std::nullptr_t>());
auto expected = common::CreateStaticByteBuffer(0x00);
common::DynamicByteBuffer buf(1);
EXPECT_EQ(1u, elem.Write(&buf));
EXPECT_TRUE(ContainersEqual(expected, buf));
}
TEST_F(SDP_DataElementTest, SetAndGet) {
DataElement elem;
elem.Set(uint8_t(5));
EXPECT_TRUE(elem.Get<uint8_t>());
EXPECT_EQ(5u, *elem.Get<uint8_t>());
EXPECT_FALSE(elem.Get<int16_t>());
elem.Set(std::string("Fuchsiađź’–"));
EXPECT_FALSE(elem.Get<uint8_t>());
EXPECT_TRUE(elem.Get<std::string>());
EXPECT_EQ(std::string("Fuchsiađź’–"), *elem.Get<std::string>());
}
TEST_F(SDP_DataElementTest, Read) {
auto buf = common::CreateStaticByteBuffer(
0x25, // Type (4: String) & Size (5: in an additional byte) = 0b00100 101
0x0B, // Bytes
'F', 'u', 'c', 'h', 's', 'i', 'a', 0xF0, 0x9F, 0x92, 0x96, // String
0xDE, 0xAD, 0xBE, 0xEF // Extra data (shouldn't be parsed)
);
DataElement elem;
EXPECT_EQ(13u, DataElement::Read(&elem, buf));
EXPECT_EQ(DataElement::Type::kString, elem.type());
EXPECT_EQ(std::string("Fuchsiađź’–"), *elem.Get<std::string>());
// Invalid - 0xDE: 0x11011 110 = 37 (invalid) + 6 (2 following byte size)
EXPECT_EQ(0u, DataElement::Read(&elem, buf.view(13)));
// elem shouldn't have been touched
EXPECT_EQ(DataElement::Type::kString, elem.type());
EXPECT_EQ(std::string("Fuchsiađź’–"), *elem.Get<std::string>());
}
TEST_F(SDP_DataElementTest, ReadUUID) {
auto buf = common::CreateStaticByteBuffer(
0x19, // Type (3: UUID) & Size (1: two bytes) = 0b00011 001
0x01, 0x00 // L2CAP
);
DataElement elem;
EXPECT_EQ(3u, DataElement::Read(&elem, buf));
EXPECT_EQ(DataElement::Type::kUuid, elem.type());
EXPECT_EQ(common::UUID(uint16_t(0x0100)), *elem.Get<common::UUID>());
auto buf2 = common::CreateStaticByteBuffer(
0x1A, // Type (3: UUID) & Size (2: four bytes) = 0b00011 010
0x01, 0x02, 0x03, 0x04);
EXPECT_EQ(5u, DataElement::Read(&elem, buf2));
EXPECT_EQ(DataElement::Type::kUuid, elem.type());
EXPECT_EQ(common::UUID(uint32_t(0x01020304)), *elem.Get<common::UUID>());
auto buf3 = common::CreateStaticByteBuffer(
0x1B, // Type (3: UUID) & Size (3: eight bytes) = 0b00011 011
0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
0x01, 0x02, 0x03, 0x04);
EXPECT_EQ(0u, DataElement::Read(&elem, buf3));
auto buf4 = common::CreateStaticByteBuffer(
0x1C, // Type (3: UUID) & Size (3: eight bytes) = 0b00011 100
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10);
EXPECT_EQ(17u, DataElement::Read(&elem, buf4));
EXPECT_EQ(DataElement::Type::kUuid, elem.type());
// UInt128 in UUID is little-endian
EXPECT_EQ(common::UUID({0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
*elem.Get<common::UUID>());
}
TEST_F(SDP_DataElementTest, Write) {
// This represents a plausible attribute_lists parameter of a
// SDP_ServiceSearchAtttributeResponse PDU for an SPP service.
std::vector<DataElement> attribute_list;
DataElement service_class_id;
service_class_id.Set(kServiceClassIdList);
DataElement service_class_value;
DataElement service_class_uuid_spp;
// SerialPort from Assigned Numbers
service_class_uuid_spp.Set(common::UUID(uint16_t(0x1101)));
std::vector<DataElement> service_class_list;
service_class_list.push_back(service_class_uuid_spp);
service_class_value.Set(service_class_list);
attribute_list.push_back(service_class_id);
attribute_list.push_back(service_class_value);
// Protocol Descriptor List
DataElement protocol_list_id;
protocol_list_id.Set(kProtocolDescriptorList);
std::vector<DataElement> protocol_list_value;
// ( L2CAP, PSM=RFCOMM )
std::vector<DataElement> protocol_l2cap;
DataElement protocol;
protocol.Set(protocol::kL2CAP);
DataElement psm;
psm.Set(uint16_t(0x0003)); // RFCOMM
protocol_l2cap.push_back(protocol);
protocol_l2cap.push_back(psm);
DataElement protocol_l2cap_elem;
protocol_l2cap_elem.Set(protocol_l2cap);
protocol_list_value.push_back(protocol_l2cap_elem);
// ( RFCOMM, CHANNEL=1 )
std::vector<DataElement> protocol_rfcomm;
protocol.Set(protocol::kRFCOMM);
DataElement chan;
chan.Set(uint8_t(1)); // Server Channel = 1
protocol_rfcomm.push_back(protocol);
protocol_rfcomm.push_back(chan);
DataElement protocol_rfcomm_elem;
protocol_rfcomm_elem.Set(protocol_rfcomm);
protocol_list_value.push_back(protocol_rfcomm_elem);
attribute_list.push_back(protocol_list_id);
DataElement protocol_list_val;
protocol_list_val.Set(protocol_list_value);
attribute_list.push_back(protocol_list_val);
// Bluetooth Profile Descriptor List
DataElement profile_descriptor_list_id;
profile_descriptor_list_id.Set(kBluetoothProfileDescriptorList);
std::vector<DataElement> profile_sequence_list;
std::vector<DataElement> spp_sequence;
DataElement profile_uuid;
profile_uuid.Set(common::UUID(uint16_t(0x1101)));
DataElement profile_version;
profile_version.Set(uint16_t(0x0102));
spp_sequence.push_back(profile_uuid);
spp_sequence.push_back(profile_version);
DataElement spp_sequence_elem;
spp_sequence_elem.Set(spp_sequence);
profile_sequence_list.push_back(spp_sequence_elem);
DataElement profile_descriptor_list_value;
profile_descriptor_list_value.Set(profile_sequence_list);
attribute_list.push_back(profile_descriptor_list_id);
attribute_list.push_back(profile_descriptor_list_value);
DataElement attribute_lists_elem;
attribute_lists_elem.Set(attribute_list);
// clang-format off
auto expected = common::CreateStaticByteBuffer(
0x35, 0x29, // Data Element Sequence with 1 byte length (41 bytes)
0x09, // uint16_t type
UpperBits(kServiceClassIdList), LowerBits(kServiceClassIdList),
0x35, 0x03, // Data Element Sequence with 1 byte length (3 bytes)
0x19, // UUID (16 bits)
0x11, 0x01, // Serial Port from assigned numbers
0x09, // uint16_t type
UpperBits(kProtocolDescriptorList), LowerBits(kProtocolDescriptorList),
0x35, 0x0F, // Data Element Sequence with 1 byte length (15 bytes)
0x35, 0x06, // Data Element Sequence with 1 byte length (6 bytes)
0x19, // Type: UUID (16 bits)
0x01, 0x00, // L2CAP UUID
0x09, // Type: uint16_t
0x00, 0x03, // RFCOMM PSM
0x35, 0x05, // Data Element Sequence with 1 byte length (5 bytes)
0x19, // Type: UUID (16 bits)
0x00, 0x03, // RFCOMM UUID
0x08, // Type: uint8_t
0x01, // RFCOMM Channel 1
0x09, // uint16_t type
UpperBits(kBluetoothProfileDescriptorList),
LowerBits(kBluetoothProfileDescriptorList),
0x35, 0x08, // Data Element Sequence with 1 byte length (8 bytes)
0x35, 0x06, // Data Element Sequence with 1 byte ength (6 bytes)
0x19, // Type: UUID (16 bits)
0x11, 0x01, // 0x1101 (SPP)
0x09, // Type: uint16_t
0x01, 0x02 // v1.2
);
// clang-format on
common::DynamicByteBuffer block(43);
size_t written = attribute_lists_elem.Write(&block);
EXPECT_EQ(expected.size(), written);
EXPECT_EQ(written, attribute_lists_elem.WriteSize());
EXPECT_TRUE(ContainersEqual(expected, block));
}
TEST_F(SDP_DataElementTest, ReadSequence) {
auto buf = common::CreateStaticByteBuffer(
0x35, 0x08, 0x09, 0x00, 0x01, // uint16_t: 1
0x0A, 0x00, 0x00, 0x00, 0x02 // uint32_t: 2
);
DataElement elem;
EXPECT_EQ(buf.size(), DataElement::Read(&elem, buf));
EXPECT_EQ(DataElement::Type::kSequence, elem.type());
auto* it = elem.At(0);
EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
EXPECT_EQ(1u, *it->Get<uint16_t>());
it = elem.At(1);
EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
EXPECT_EQ(2u, *it->Get<uint32_t>());
}
} // namespace
} // namespace sdp
} // namespace btlib