1 /******************************************************************************
2  *
3  *  Copyright 2018 The Android Open Source Project
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 
19 #include "gatt/database_builder.h"
20 
21 #include <gtest/gtest.h>
22 
23 #include <iterator>
24 #include <utility>
25 
26 #include "types/bluetooth/uuid.h"
27 
28 using bluetooth::Uuid;
29 
30 namespace gatt {
31 
32 namespace {
33 /* make_pair doesn't work well with ASSERT_EQ, have own helper instead */
make_pair_u16(uint16_t first,uint16_t second)34 inline std::pair<uint16_t, uint16_t> make_pair_u16(uint16_t first,
35                                                    uint16_t second) {
36   return std::make_pair(first, second);
37 }
38 
39 Uuid SERVICE_1_UUID = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb");
40 Uuid SERVICE_2_UUID = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb");
41 Uuid SERVICE_3_UUID = Uuid::FromString("0000180f-0000-1000-8000-00805f9b34fb");
42 Uuid SERVICE_4_UUID = Uuid::FromString("0000fef5-0000-1000-8000-00805f9b34fb");
43 Uuid SERVICE_5_UUID = Uuid::FromString("0000180a-0000-1000-8000-00805f9b34fb");
44 Uuid SERVICE_1_CHAR_1_UUID =
45     Uuid::FromString("00002a00-0000-1000-8000-00805f9b34fb");
46 Uuid SERVICE_1_CHAR_1_DESC_1_UUID =
47     Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
48 
49 }  // namespace
50 
51 /* Verify adding empty service works ok */
TEST(DatabaseBuilderTest,EmptyServiceAddTest)52 TEST(DatabaseBuilderTest, EmptyServiceAddTest) {
53   DatabaseBuilder builder;
54 
55   EXPECT_FALSE(builder.InProgress());
56 
57   // Simple database, just one empty
58   builder.AddService(0x0001, 0x0001, SERVICE_1_UUID, true);
59   EXPECT_FALSE(builder.StartNextServiceExploration());
60 
61   Database result = builder.Build();
62 
63   // verify that the returned database matches what was discovered
64   auto service = result.Services().begin();
65   ASSERT_EQ(service->handle, 0x0001);
66   ASSERT_EQ(service->end_handle, 0x0001);
67   ASSERT_EQ(service->is_primary, true);
68   ASSERT_EQ(service->uuid, SERVICE_1_UUID);
69 }
70 
71 /* Verify adding service, characteristic and descriptor work */
TEST(DatabaseBuilderTest,DescriptorAddTest)72 TEST(DatabaseBuilderTest, DescriptorAddTest) {
73   DatabaseBuilder builder;
74 
75   EXPECT_FALSE(builder.InProgress());
76 
77   // Simple database, just one empty
78   builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
79   builder.AddCharacteristic(0x0002, 0x0003, SERVICE_1_CHAR_1_UUID, 0x02);
80   builder.AddDescriptor(0x0004, SERVICE_1_CHAR_1_DESC_1_UUID);
81 
82   Database result = builder.Build();
83 
84   // verify that the returned database matches what was discovered
85   auto service = result.Services().begin();
86   ASSERT_EQ(service->handle, 0x0001);
87   ASSERT_EQ(service->end_handle, 0x000f);
88   ASSERT_EQ(service->is_primary, true);
89   ASSERT_EQ(service->uuid, SERVICE_1_UUID);
90 
91   ASSERT_EQ(service->characteristics[0].uuid, SERVICE_1_CHAR_1_UUID);
92   ASSERT_EQ(service->characteristics[0].declaration_handle, 0x0002);
93   ASSERT_EQ(service->characteristics[0].value_handle, 0x0003);
94   ASSERT_EQ(service->characteristics[0].properties, 0x02);
95 
96   ASSERT_EQ(service->characteristics[0].descriptors[0].uuid,
97             SERVICE_1_CHAR_1_DESC_1_UUID);
98   ASSERT_EQ(service->characteristics[0].descriptors[0].handle, 0x0004);
99 }
100 
101 /* This test verifies that DatabaseBuilder properly handle discovery of
102  * secondary service, that is added to the discovery queue from included service
103  * definition. Such service might come out of order.  */
TEST(DatabaseBuilderTest,SecondaryServiceOutOfOrderTest)104 TEST(DatabaseBuilderTest, SecondaryServiceOutOfOrderTest) {
105   DatabaseBuilder builder;
106 
107   EXPECT_FALSE(builder.InProgress());
108 
109   // At start of discovery, builder will receive All services in order from
110   // lower layers.
111   builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
112   builder.AddService(0x0030, 0x003f, SERVICE_3_UUID, true);
113   builder.AddService(0x0050, 0x005f, SERVICE_5_UUID, true);
114 
115   // First service skipped, no place for handles
116   EXPECT_TRUE(builder.StartNextServiceExploration());
117   ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0001, 0x000f));
118 
119   // For this test, content of first service is irrevelant
120 
121   EXPECT_TRUE(builder.StartNextServiceExploration());
122   // Grabbing first service, to start Included Service and Characteristic
123   // discovery
124   ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0030, 0x003f));
125 
126   builder.AddIncludedService(0x0031, SERVICE_4_UUID, 0x0040, 0x004f);
127   builder.AddIncludedService(0x0032, SERVICE_2_UUID, 0x0020, 0x002f);
128 
129   /* Secondary service exploration */
130   EXPECT_TRUE(builder.StartNextServiceExploration());
131   ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0020, 0x002f));
132 
133   /* Secondary service exploration */
134   EXPECT_TRUE(builder.StartNextServiceExploration());
135   ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0040, 0x004f));
136 
137   /* Back to primary service exploration */
138   EXPECT_TRUE(builder.StartNextServiceExploration());
139   ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0050, 0x005f));
140 
141   Database result = builder.Build();
142 
143   // verify that the returned database matches what was discovered
144   auto service = result.Services().begin();
145   ASSERT_EQ(service->handle, 0x0001);
146   ASSERT_EQ(service->is_primary, true);
147   ASSERT_EQ(service->uuid, SERVICE_1_UUID);
148 
149   service++;
150   ASSERT_EQ(service->handle, 0x0020);
151   ASSERT_EQ(service->end_handle, 0x002f);
152   ASSERT_EQ(service->uuid, SERVICE_2_UUID);
153   ASSERT_EQ(service->is_primary, false);
154 
155   service++;
156   ASSERT_EQ(service->handle, 0x0030);
157   ASSERT_EQ(service->end_handle, 0x003f);
158   ASSERT_EQ(service->uuid, SERVICE_3_UUID);
159   ASSERT_EQ(service->is_primary, true);
160   ASSERT_EQ(service->included_services.size(), (size_t)2);
161   ASSERT_EQ(service->included_services[0].start_handle, 0x0040);
162   ASSERT_EQ(service->included_services[0].end_handle, 0x004f);
163   ASSERT_EQ(service->included_services[1].start_handle, 0x0020);
164   ASSERT_EQ(service->included_services[1].end_handle, 0x002f);
165 
166   service++;
167   ASSERT_EQ(service->handle, 0x0040);
168   ASSERT_EQ(service->uuid, SERVICE_4_UUID);
169   ASSERT_EQ(service->is_primary, false);
170 
171   service++;
172   ASSERT_EQ(service->handle, 0x0050);
173   ASSERT_EQ(service->uuid, SERVICE_5_UUID);
174   ASSERT_EQ(service->is_primary, true);
175 
176   service++;
177   ASSERT_EQ(service, result.Services().end());
178 }
179 
180 }  // namespace gatt
181