1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include "stack/include/sdp_api.h"
20 #include "stack/include/sdpdefs.h"
21 #include "stack/sdp/sdpint.h"
22 
23 namespace {
24 constexpr char service_name[] = "TestServiceName";
25 constexpr uint32_t kFirstRecordHandle = 0x10000;
26 }  // namespace
27 
28 using bluetooth::legacy::stack::sdp::get_legacy_stack_sdp_api;
29 
30 class StackSdpDbTest : public ::testing::Test {
31  protected:
SetUp()32   void SetUp() override {
33     // Ensure no records exist in global state
34     ASSERT_EQ((uint16_t)0, sdp_cb.server_db.num_records);
35   }
36 
TearDown()37   void TearDown() override {
38     // Ensure all records have been deleted from global state
39     ASSERT_EQ((uint16_t)0, sdp_cb.server_db.num_records);
40   }
41 };
42 
TEST_F(StackSdpDbTest,SDP_AddAttribute__create_record)43 TEST_F(StackSdpDbTest, SDP_AddAttribute__create_record) {
44   uint32_t record_handle =
45       get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();
46 
47   ASSERT_NE((uint32_t)0, record_handle);
48   ASSERT_EQ((uint16_t)1, sdp_cb.server_db.num_records);
49 
50   tSDP_RECORD* record = sdp_db_find_record(record_handle);
51   ASSERT_TRUE(record != nullptr);
52 
53   // The sdp handle is always the first attribute
54   ASSERT_EQ((uint16_t)1, record->num_attributes);
55   ASSERT_EQ(kFirstRecordHandle, record->record_handle);
56   ASSERT_EQ(sizeof(uint32_t), record->free_pad_ptr);
57 
58   ASSERT_TRUE(
59       get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(record_handle));
60 }
61 
TEST_F(StackSdpDbTest,SDP_AddAttribute__add_service_name)62 TEST_F(StackSdpDbTest, SDP_AddAttribute__add_service_name) {
63   uint32_t record_handle =
64       get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();
65 
66   ASSERT_NE((uint32_t)0, record_handle);
67   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
68       record_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
69       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
70 
71   tSDP_RECORD* record = sdp_db_find_record(record_handle);
72   ASSERT_TRUE(record != nullptr);
73 
74   // The sdp handle is always the first attribute
75   ASSERT_EQ((uint16_t)(1 /* record_handle */ + 1 /* service name */),
76             record->num_attributes);
77   ASSERT_EQ(kFirstRecordHandle, record->record_handle);
78   ASSERT_EQ(sizeof(uint32_t) + strlen(service_name) + 1, record->free_pad_ptr);
79 
80   const tSDP_ATTRIBUTE* attribute = sdp_db_find_attr_in_rec(
81       record, ATTR_ID_SERVICE_NAME, ATTR_ID_SERVICE_NAME);
82   ASSERT_TRUE(attribute != nullptr);
83 
84   ASSERT_TRUE(
85       get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(record_handle));
86 }
87 
TEST_F(StackSdpDbTest,SDP_AddAttribute__three_attributes)88 TEST_F(StackSdpDbTest, SDP_AddAttribute__three_attributes) {
89   uint32_t record_handle =
90       get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();
91 
92   ASSERT_NE((uint32_t)0, record_handle);
93 
94   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
95       record_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
96       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
97   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
98       record_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
99       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
100   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
101       record_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
102       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
103 
104   tSDP_RECORD* record = sdp_db_find_record(record_handle);
105   ASSERT_TRUE(record != nullptr);
106 
107   // The sdp handle is always the first attribute
108   ASSERT_EQ((uint16_t)(1 /* record_handle */ + 3 /* service name */),
109             record->num_attributes);
110   ASSERT_EQ(kFirstRecordHandle, record->record_handle);
111   ASSERT_EQ(sizeof(uint32_t) + (3 * (strlen(service_name) + 1)),
112             record->free_pad_ptr);
113 
114   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_SERVICE_NAME,
115                                       ATTR_ID_SERVICE_NAME) != nullptr);
116   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_SERVICE_DESCRIPTION,
117                                       ATTR_ID_SERVICE_DESCRIPTION) != nullptr);
118   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_PROVIDER_NAME,
119                                       ATTR_ID_PROVIDER_NAME) != nullptr);
120 
121   ASSERT_TRUE(
122       get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(record_handle));
123 }
124 
TEST_F(StackSdpDbTest,SDP_AddAttribute__too_many_attributes)125 TEST_F(StackSdpDbTest, SDP_AddAttribute__too_many_attributes) {
126   uint32_t record_handle =
127       get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();
128   ASSERT_NE((uint32_t)0, record_handle);
129 
130   uint8_t boolean = 1;
131   for (size_t i = 0; i < SDP_MAX_REC_ATTR; i++) {
132     ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
133         record_handle, (uint16_t)i, BOOLEAN_DESC_TYPE, boolean, &boolean));
134   }
135 
136   ASSERT_FALSE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
137       record_handle, SDP_MAX_REC_ATTR + 1, BOOLEAN_DESC_TYPE, boolean,
138       &boolean));
139   ASSERT_TRUE(
140       get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(record_handle));
141 }
142 
TEST_F(StackSdpDbTest,SDP_AddAttribute__three_attributes_replace_middle)143 TEST_F(StackSdpDbTest, SDP_AddAttribute__three_attributes_replace_middle) {
144   uint32_t record_handle =
145       get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();
146 
147   ASSERT_NE((uint32_t)0, record_handle);
148 
149   // Add 3 attributes to this record handle
150   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
151       record_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
152       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
153   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
154       record_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
155       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
156   ASSERT_TRUE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
157       record_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
158       (uint32_t)(strlen(service_name) + 1), (uint8_t*)service_name));
159 
160   tSDP_RECORD* record = sdp_db_find_record(record_handle);
161   ASSERT_TRUE(record != nullptr);
162 
163   // The sdp handle is always the first attribute
164   ASSERT_EQ((uint16_t)(1 /* record_handle */ + 3 /* attribute count */),
165             record->num_attributes);
166   ASSERT_EQ(kFirstRecordHandle, record->record_handle);
167   ASSERT_EQ(sizeof(uint32_t) + (3 * (strlen(service_name) + 1)),
168             record->free_pad_ptr);
169 
170   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_SERVICE_NAME,
171                                       ATTR_ID_SERVICE_NAME) != nullptr);
172   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_SERVICE_DESCRIPTION,
173                                       ATTR_ID_SERVICE_DESCRIPTION) != nullptr);
174   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_PROVIDER_NAME,
175                                       ATTR_ID_PROVIDER_NAME) != nullptr);
176 
177   // Attempt to replace the middle attribute with an invalid attribute
178   ASSERT_FALSE(get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
179       record_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
180       (uint32_t)0, (uint8_t*)nullptr));
181 
182   // Ensure database is still intact.
183   ASSERT_EQ((uint16_t)(1 /* record_handle */ + 3 /* attribute count */),
184             record->num_attributes);
185   ASSERT_EQ(kFirstRecordHandle, record->record_handle);
186   ASSERT_EQ(sizeof(uint32_t) + (3 * (strlen(service_name) + 1)),
187             record->free_pad_ptr);
188 
189   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_SERVICE_NAME,
190                                       ATTR_ID_SERVICE_NAME) != nullptr);
191   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_SERVICE_DESCRIPTION,
192                                       ATTR_ID_SERVICE_DESCRIPTION) != nullptr);
193   ASSERT_TRUE(sdp_db_find_attr_in_rec(record, ATTR_ID_PROVIDER_NAME,
194                                       ATTR_ID_PROVIDER_NAME) != nullptr);
195 
196   ASSERT_TRUE(
197       get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(record_handle));
198 }
199