--- /dev/null
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "data_element_reader.h"
+
+#include <base/logging.h>
+#include <type_traits>
+
+#include "sdp_logging_helper.h"
+
+// A helper macro that can verify that there is enough data remaining in the
+// reader to extract without overflowing. end_ - it_ should never be negative
+// so casting it to a size_t is always safe. If it does fail, set it_ to end_
+// so that all additional readings fail.
+#define CHECK_REMAINING_LEN(x) \
+ do { \
+ if ((size_t)(end_ - it_) < x) { \
+ LOG(WARNING) << __func__ << ": Extract would read past end of data."; \
+ return ParseFail(); \
+ } \
+ } while (0)
+
+namespace bluetooth {
+namespace sdp {
+
+DataElementReader::DataElement DataElementReader::ReadNext() {
+ if (it_ > end_) LOG(FATAL) << "Beginning of buffer is past end of buffer.";
+ if (it_ == end_) return std::monostate();
+
+ uint8_t descriptor = *it_++;
+ DataElementType type = static_cast<DataElementType>(descriptor >> 3);
+ DataElementSize size = static_cast<DataElementSize>(descriptor & 0b00000111);
+
+ // All types with a value greater than URL are currently reserved.
+ if (type > DataElementType::MAX_VALUE) {
+ LOG(WARNING) << __func__ << ": Trying to use a reserved data element type";
+ return ParseFail();
+ }
+
+ switch (type) {
+ case DataElementType::BOOLEAN:
+ if (size != DataElementSize::BYTE1) {
+ LOG(WARNING) << __func__ << ": Invalid size for bool: " << size;
+ return ParseFail();
+ }
+
+ CHECK_REMAINING_LEN(1);
+ return (it_.extract<uint8_t>() != 0);
+ case DataElementType::SIGNED_INT:
+ return ReadSignedInt(size);
+ case DataElementType::UNSIGNED_INT:
+ return ReadUnsignedInt(size);
+ case DataElementType::UUID:
+ return ReadUuid(size);
+ case DataElementType::STRING:
+ return ReadString(size);
+ case DataElementType::DATA_ELEMENT_SEQUENCE:
+ return ReadSequence(size);
+ default:
+ // TODO: The other data element types are never used in the previous SDP
+ // implementation. We should properly handle them in the future though
+ // for completeness.
+ LOG(ERROR) << __func__ << ": Unhandled Data Element Type: " << type;
+ }
+
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ParseFail() {
+ it_ = end_;
+ return std::monostate();
+}
+
+template <class IntegerType>
+DataElementReader::DataElement DataElementReader::ReadInteger() {
+ static_assert(std::is_integral<IntegerType>::value,
+ "ReadInteger requires an integral type.");
+
+ CHECK_REMAINING_LEN(sizeof(IntegerType));
+ return it_.extractBE<IntegerType>();
+}
+
+DataElementReader::DataElement DataElementReader::ReadLargeInt() {
+ CHECK_REMAINING_LEN(16);
+
+ std::array<uint8_t, 16> array;
+ for (size_t i = 0; i < sizeof(uint8_t[16]); i++) {
+ array[i] = it_.extract<uint8_t>();
+ }
+
+ return array;
+}
+
+DataElementReader::DataElement DataElementReader::ReadSignedInt(
+ DataElementSize size) {
+ switch (size) {
+ case DataElementSize::BYTE1:
+ return ReadInteger<int8_t>();
+ case DataElementSize::BYTE2:
+ return ReadInteger<int16_t>();
+ case DataElementSize::BYTE4:
+ return ReadInteger<int32_t>();
+ case DataElementSize::BYTE8:
+ return ReadInteger<int64_t>();
+ case DataElementSize::BYTE16:
+ return ReadLargeInt();
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for int: " << size;
+ }
+
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ReadUnsignedInt(
+ DataElementSize size) {
+ switch (size) {
+ case DataElementSize::BYTE1:
+ return ReadInteger<uint8_t>();
+ case DataElementSize::BYTE2:
+ return ReadInteger<uint16_t>();
+ case DataElementSize::BYTE4:
+ return ReadInteger<uint32_t>();
+ case DataElementSize::BYTE8:
+ return ReadInteger<uint64_t>();
+ case DataElementSize::BYTE16:
+ return ReadLargeInt();
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for uint: " << size;
+ }
+
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ReadUuid(
+ DataElementSize size) {
+ if (size == DataElementSize::BYTE2) {
+ CHECK_REMAINING_LEN(2);
+ return Uuid::From16Bit(it_.extractBE<uint16_t>());
+ }
+
+ if (size == DataElementSize::BYTE4) {
+ CHECK_REMAINING_LEN(4);
+ return Uuid::From32Bit(it_.extractBE<uint32_t>());
+ }
+
+ if (size == DataElementSize::BYTE16) {
+ CHECK_REMAINING_LEN(16);
+
+ Uuid::UUID128Bit uuid_array;
+ for (int i = 0; i < 16; i++) {
+ uuid_array[i] = it_.extract<uint8_t>();
+ }
+
+ return Uuid::From128BitBE(uuid_array);
+ }
+
+ LOG(WARNING) << __func__ << ": Invalid size for UUID: " << size;
+ return ParseFail();
+}
+
+DataElementReader::DataElement DataElementReader::ReadString(
+ DataElementSize size) {
+ uint32_t num_bytes = 0;
+
+ switch (size) {
+ case DataElementSize::ADDITIONAL_8BIT:
+ CHECK_REMAINING_LEN(1);
+ num_bytes = it_.extractBE<uint8_t>();
+ break;
+ case DataElementSize::ADDITIONAL_16BIT:
+ CHECK_REMAINING_LEN(2);
+ num_bytes = it_.extractBE<uint16_t>();
+ break;
+ case DataElementSize::ADDITIONAL_32BIT:
+ CHECK_REMAINING_LEN(4);
+ num_bytes = it_.extractBE<uint32_t>();
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for string: " << size;
+ return ParseFail();
+ }
+
+ CHECK_REMAINING_LEN(num_bytes);
+
+ std::string str;
+ for (uint32_t i = 0; i < num_bytes; i++) {
+ str.push_back(it_.extractBE<uint8_t>());
+ }
+
+ return str;
+}
+
+DataElementReader::DataElement DataElementReader::ReadSequence(
+ DataElementSize size) {
+ uint32_t num_bytes = 0;
+
+ switch (size) {
+ case DataElementSize::ADDITIONAL_8BIT:
+ CHECK_REMAINING_LEN(1);
+ num_bytes = it_.extractBE<uint8_t>();
+ break;
+ case DataElementSize::ADDITIONAL_16BIT:
+ CHECK_REMAINING_LEN(2);
+ num_bytes = it_.extractBE<uint16_t>();
+ break;
+ case DataElementSize::ADDITIONAL_32BIT:
+ CHECK_REMAINING_LEN(4);
+ num_bytes = it_.extractBE<uint32_t>();
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": Invalid size for string: " << size;
+ return ParseFail();
+ }
+
+ CHECK_REMAINING_LEN(num_bytes);
+
+ // Create a parser that points to the beginning of the next sequence and move
+ // the iterator to past the end of the new sequence.
+ auto&& temp = DataElementReader(it_, it_ + num_bytes);
+ it_ += num_bytes;
+ return std::move(temp);
+}
+
+} // namespace sdp
+} // namespace bluetooth
--- /dev/null
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+#include "common/data_element_reader.h"
+
+namespace bluetooth {
+namespace sdp {
+
+using namespace testing;
+using DataElement = DataElementReader::DataElement;
+
+// A helper class to help work with the Data Element classes.
+class ReaderPacket : public ::bluetooth::Packet {
+ public:
+ using Packet::Packet;
+
+ static std::shared_ptr<ReaderPacket> Make(std::vector<uint8_t> payload) {
+ auto pkt = std::shared_ptr<ReaderPacket>(new ReaderPacket());
+ pkt->packet_start_index_ = 0;
+ pkt->packet_end_index_ = payload.size();
+ pkt->data_ = std::make_shared<std::vector<uint8_t>>(std::move(payload));
+ return pkt;
+ }
+
+ std::string ToString() const override { return ""; }
+ bool IsValid() const override { return true; }
+ std::pair<size_t, size_t> GetPayloadIndecies() const override {
+ return std::pair<size_t, size_t>(packet_start_index_, packet_end_index_);
+ }
+};
+
+bool operator!=(DataElementReader a, DataElementReader b);
+
+// A helper function to help compare DataElementReader objects.
+bool operator==(DataElementReader a, DataElementReader b) {
+ while (true) {
+ DataElement a_elem = a.ReadNext();
+ DataElement b_elem = b.ReadNext();
+
+ if (a_elem != b_elem) return false;
+
+ // If we get here that means both a and b have reached the end.
+ if (a_elem == DataElement(std::monostate())) break;
+ }
+
+ return true;
+}
+
+bool operator!=(DataElementReader a, DataElementReader b) { return !(a == b); }
+
+// A helper function to convert a type and a size to a descriptor byte.
+constexpr uint8_t Desc(DataElementType t, DataElementSize s) {
+ return static_cast<uint8_t>(t) << 3 | static_cast<uint8_t>(s);
+}
+
+// Helper that can create a Data Element reader from a vector.
+DataElementReader CreateReader(std::vector<uint8_t> payload) {
+ auto packet = ReaderPacket::Make(std::move(payload));
+ return DataElementReader(packet->begin(), packet->end());
+}
+
+// Test all the valid cases of reading the next Data Element.
+using ValidTestParam = std::tuple<std::vector<uint8_t>, DataElement>;
+class ValidReadTest : public TestWithParam<ValidTestParam> {};
+
+std::vector<ValidTestParam> valid_values = {
+ // Boolean Tests
+ ValidTestParam{
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01},
+ true,
+ },
+ ValidTestParam{
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ false,
+ },
+
+ // Signed Integer Tests
+ ValidTestParam{
+ {Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE1), 0xFF},
+ static_cast<int8_t>(-1)},
+ ValidTestParam{
+ {Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0xFF, 0xFF},
+ static_cast<int16_t>(-1)},
+ ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE4),
+ 0xFF, 0xFF, 0xFF, 0xFF},
+ static_cast<int32_t>(-1)},
+ ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE8),
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ static_cast<int64_t>(-1)},
+ ValidTestParam{{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE16),
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ std::array<uint8_t, 16>{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF}},
+
+ // Unsigned Integer Tests
+ ValidTestParam{
+ {Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE1), 0x01},
+ static_cast<uint8_t>(1)},
+ ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE2),
+ 0x00, 0x01},
+ static_cast<uint16_t>(1)},
+ ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE4),
+ 0x00, 0x00, 0x00, 0x01},
+ static_cast<uint32_t>(1)},
+ ValidTestParam{{Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE8),
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ static_cast<uint64_t>(1)},
+ ValidTestParam{
+ {Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE16), 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01},
+ std::array<uint8_t, 16>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01}},
+
+ // UUID Tests
+ ValidTestParam{
+ {Desc(DataElementType::UUID, DataElementSize::BYTE2), 0x01, 0x02},
+ Uuid::From16Bit(0x0102)},
+ ValidTestParam{{Desc(DataElementType::UUID, DataElementSize::BYTE4), 0x01,
+ 0x02, 0x03, 0x04},
+ Uuid::From32Bit(0x01020304)},
+ ValidTestParam{
+ {Desc(DataElementType::UUID, DataElementSize::BYTE16), 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F},
+ Uuid::From128BitBE({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F})},
+
+ // String Tests
+ ValidTestParam{
+ {Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT), 0x05,
+ 'T', 'e', 's', 't', '1'},
+ std::string("Test1")},
+ ValidTestParam{
+ {Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_16BIT), 0x00,
+ 0x05, 'T', 'e', 's', 't', '2'},
+ std::string("Test2")},
+ ValidTestParam{
+ {Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_32BIT), 0x00,
+ 0x00, 0x00, 0x05, 'T', 'e', 's', 't', '3'},
+ std::string("Test3")},
+
+ // Nested Data Element List Tests
+ ValidTestParam{
+ {Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT),
+ 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ CreateReader(
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})},
+ ValidTestParam{
+ {Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_16BIT),
+ 0x00, 0x04, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1),
+ 0x01, Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ CreateReader(
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})},
+ ValidTestParam{
+ {Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_32BIT),
+ 0x00, 0x00, 0x00, 0x04,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00},
+ CreateReader(
+ {Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00})},
+};
+
+INSTANTIATE_TEST_CASE_P(ReadNext, ValidReadTest, ValuesIn(valid_values));
+TEST_P(ValidReadTest, Test) {
+ auto packet = ReaderPacket::Make(std::get<0>(GetParam()));
+ auto value = std::get<1>(GetParam());
+
+ DataElementReader reader(packet->begin(), packet->end());
+ auto read_value = reader.ReadNext();
+
+ ASSERT_EQ(value, read_value);
+
+ // Test that there is no additional data to read.
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that a nested reader is correctly bounded and can't read past its
+// defined end.
+TEST(ReadNext, BoundedSubreaderTest) {
+ std::vector<uint8_t> payload = {
+ // Subsequence descriptor byte.
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT),
+ // Subsequence length.
+ 0x04,
+ // Subsequence that contains two booleans with values true and false.
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x01,
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1), 0x00,
+ // Additional int16 at the end of the original sequence.
+ Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2), 0x01, 0x23};
+
+ auto packet = ReaderPacket::Make(payload);
+ DataElementReader reader(packet->begin(), packet->end());
+
+ // The first thing read should be the subsequence.
+ auto data_element = reader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<DataElementReader>(data_element));
+
+ // Check that the subsequence matches the premade sequence.
+ auto subreader = std::get<DataElementReader>(data_element);
+ data_element = subreader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<bool>(data_element));
+ ASSERT_TRUE(std::get<bool>(data_element));
+ data_element = subreader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<bool>(data_element));
+ ASSERT_FALSE(std::get<bool>(data_element));
+
+ // Check that there is no additional data to be read from the subreader.
+ ASSERT_EQ(subreader.ReadNext(), DataElement(std::monostate()));
+
+ // Check that we can still read the int16 from the original reader.
+ data_element = reader.ReadNext();
+ ASSERT_TRUE(std::holds_alternative<int16_t>(data_element));
+ auto int16_value = std::get<int16_t>(data_element);
+ ASSERT_EQ(int16_value, 0x0123);
+
+ // Check that there is no additional data to be read from the base reader.
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that trying to read an empty packet fails.
+TEST(ReadNext, NoDataTest) {
+ auto packet = ReaderPacket::Make({});
+ DataElementReader reader(packet->begin(), packet->end());
+
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that using a reserved value for type fails.
+TEST(ReadNext, InvalidTypeTest) {
+ auto packet = ReaderPacket::Make({0xFF});
+ DataElementReader reader(packet->begin(), packet->end());
+
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test all invalid parses due to incorrect lengths or invalid sizes. All tests
+// should return std::monostate.
+using InvalidTestParam = std::vector<uint8_t>;
+class InvalidReadTest : public TestWithParam<InvalidTestParam> {};
+
+std::vector<InvalidTestParam> invalid_values = {
+ // Boolean Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::BOOLEAN, DataElementSize::BYTE2),
+ },
+ // Insufficient data.
+ InvalidTestParam{Desc(DataElementType::BOOLEAN, DataElementSize::BYTE1)},
+
+ // Signed Integer Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::SIGNED_INT, DataElementSize::ADDITIONAL_8BIT)},
+ // 1 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE1)},
+ // 2 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE2),
+ 0x00},
+ // 4 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE4),
+ 0x00, 0x00, 0x00},
+ // 8 Byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE8),
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ // 16 Byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::SIGNED_INT, DataElementSize::BYTE16),
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00},
+
+ // Unsigned Integer Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::ADDITIONAL_8BIT)},
+ // 1 byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE1)},
+ // 2 byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE2), 0x00},
+ // 4 byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE4), 0x00, 0x00,
+ 0x00},
+ // 8 Byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE8), 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00},
+ // 16 Byte insufficient data.
+ InvalidTestParam{
+ Desc(DataElementType::UNSIGNED_INT, DataElementSize::BYTE16), 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ // UUID Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::UUID, DataElementSize::ADDITIONAL_8BIT)},
+ // 2 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE2), 0x00},
+ // 4 byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE4), 0x00,
+ 0x00, 0x00},
+ // 16 Byte insufficient data.
+ InvalidTestParam{Desc(DataElementType::UUID, DataElementSize::BYTE16), 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00},
+
+ // String Tests:
+ // Invalid size field.
+ InvalidTestParam{Desc(DataElementType::STRING, DataElementSize::BYTE1)},
+ // Insufficient data for additional 8 bits len.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT)},
+ // Insufficient data for additional 16 bits len.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_16BIT),
+ 0x00,
+ },
+ // Insufficient data for additional 32 bit len.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_32BIT),
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+ // Insufficient data for reported length.
+ InvalidTestParam{
+ Desc(DataElementType::STRING, DataElementSize::ADDITIONAL_8BIT), 0x04,
+ '1', '2', '3'},
+
+ // Nested Data Element List Tests:
+ // Invalid size field.
+ InvalidTestParam{
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE, DataElementSize::BYTE1)},
+ // Insufficient data for additional 8 bits len.
+ InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT)},
+ // Insufficient data for additional 16 bits len.
+ InvalidTestParam{
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_16BIT),
+ 0x00,
+ },
+ // Insufficient data for additional 32 bit len.
+ InvalidTestParam{
+ Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_32BIT),
+ 0x00,
+ 0x00,
+ 0x00,
+ },
+ // Insufficient data for reported length.
+ InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_SEQUENCE,
+ DataElementSize::ADDITIONAL_8BIT),
+ 0x04, 0x00, 0x00, 0x00},
+
+ // Unhandled Data Element Types Tests:
+ // NOTE: These tests should go away as we begin to handle the types.
+ // Nil Type.
+ InvalidTestParam{Desc(DataElementType::NIL, DataElementSize::BYTE1)},
+ // Data Element Alternative List Type.
+ InvalidTestParam{Desc(DataElementType::DATA_ELEMENT_ALTERNATIVE,
+ DataElementSize::ADDITIONAL_8BIT),
+ 0x00},
+ // URL Type.
+ InvalidTestParam{
+ Desc(DataElementType::URL, DataElementSize::ADDITIONAL_8BIT), 0x00}};
+
+INSTANTIATE_TEST_CASE_P(ReadNext, InvalidReadTest, ValuesIn(invalid_values));
+TEST_P(InvalidReadTest, Test) {
+ auto packet = ReaderPacket::Make(GetParam());
+ DataElementReader reader(packet->begin(), packet->end());
+
+ ASSERT_EQ(reader.ReadNext(), DataElement(std::monostate()));
+}
+
+// Test that trying to read from a reader with start > end crashes.
+TEST(DataElementReader, BadBoundsDeathTest) {
+ auto packet = ReaderPacket::Make({0x00, 0x00, 0x00, 0x00});
+ DataElementReader reader(packet->end(), packet->begin());
+ ASSERT_DEATH(reader.ReadNext(), "Beginning of buffer is past end of buffer.");
+}
+
+} // namespace sdp
+} // namespace bluetooth