| /****************************************************************************** |
| * |
| * 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 "gatt/database_builder.h" |
| |
| #include <base/logging.h> |
| #include <gtest/gtest.h> |
| |
| #include <iterator> |
| #include <utility> |
| |
| #include "types/bluetooth/uuid.h" |
| |
| using bluetooth::Uuid; |
| |
| namespace gatt { |
| |
| namespace { |
| /* make_pair doesn't work well with ASSERT_EQ, have own helper instead */ |
| inline std::pair<uint16_t, uint16_t> make_pair_u16(uint16_t first, |
| uint16_t second) { |
| return std::make_pair(first, second); |
| } |
| |
| Uuid SERVICE_1_UUID = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb"); |
| Uuid SERVICE_2_UUID = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb"); |
| Uuid SERVICE_3_UUID = Uuid::FromString("0000180f-0000-1000-8000-00805f9b34fb"); |
| Uuid SERVICE_4_UUID = Uuid::FromString("0000fef5-0000-1000-8000-00805f9b34fb"); |
| Uuid SERVICE_5_UUID = Uuid::FromString("0000180a-0000-1000-8000-00805f9b34fb"); |
| Uuid SERVICE_1_CHAR_1_UUID = |
| Uuid::FromString("00002a00-0000-1000-8000-00805f9b34fb"); |
| Uuid SERVICE_1_CHAR_1_DESC_1_UUID = |
| Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb"); |
| |
| } // namespace |
| |
| /* Verify adding empty service works ok */ |
| TEST(DatabaseBuilderTest, EmptyServiceAddTest) { |
| DatabaseBuilder builder; |
| |
| EXPECT_FALSE(builder.InProgress()); |
| |
| // Simple database, just one empty |
| builder.AddService(0x0001, 0x0001, SERVICE_1_UUID, true); |
| EXPECT_FALSE(builder.StartNextServiceExploration()); |
| |
| Database result = builder.Build(); |
| |
| // verify that the returned database matches what was discovered |
| auto service = result.Services().begin(); |
| ASSERT_EQ(service->handle, 0x0001); |
| ASSERT_EQ(service->end_handle, 0x0001); |
| ASSERT_EQ(service->is_primary, true); |
| ASSERT_EQ(service->uuid, SERVICE_1_UUID); |
| } |
| |
| /* Verify adding service, characteristic and descriptor work */ |
| TEST(DatabaseBuilderTest, DescriptorAddTest) { |
| DatabaseBuilder builder; |
| |
| EXPECT_FALSE(builder.InProgress()); |
| |
| // Simple database, just one empty |
| builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true); |
| builder.AddCharacteristic(0x0002, 0x0003, SERVICE_1_CHAR_1_UUID, 0x02); |
| builder.AddDescriptor(0x0004, SERVICE_1_CHAR_1_DESC_1_UUID); |
| |
| Database result = builder.Build(); |
| |
| // verify that the returned database matches what was discovered |
| auto service = result.Services().begin(); |
| ASSERT_EQ(service->handle, 0x0001); |
| ASSERT_EQ(service->end_handle, 0x000f); |
| ASSERT_EQ(service->is_primary, true); |
| ASSERT_EQ(service->uuid, SERVICE_1_UUID); |
| |
| ASSERT_EQ(service->characteristics[0].uuid, SERVICE_1_CHAR_1_UUID); |
| ASSERT_EQ(service->characteristics[0].declaration_handle, 0x0002); |
| ASSERT_EQ(service->characteristics[0].value_handle, 0x0003); |
| ASSERT_EQ(service->characteristics[0].properties, 0x02); |
| |
| ASSERT_EQ(service->characteristics[0].descriptors[0].uuid, |
| SERVICE_1_CHAR_1_DESC_1_UUID); |
| ASSERT_EQ(service->characteristics[0].descriptors[0].handle, 0x0004); |
| } |
| |
| /* This test verifies that DatabaseBuilder properly handle discovery of |
| * secondary service, that is added to the discovery queue from included service |
| * definition. Such service might come out of order. */ |
| TEST(DatabaseBuilderTest, SecondaryServiceOutOfOrderTest) { |
| DatabaseBuilder builder; |
| |
| EXPECT_FALSE(builder.InProgress()); |
| |
| // At start of discovery, builder will receive All services in order from |
| // lower layers. |
| builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true); |
| builder.AddService(0x0030, 0x003f, SERVICE_3_UUID, true); |
| builder.AddService(0x0050, 0x005f, SERVICE_5_UUID, true); |
| |
| // First service skipped, no place for handles |
| EXPECT_TRUE(builder.StartNextServiceExploration()); |
| ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0001, 0x000f)); |
| |
| // For this test, content of first service is irrevelant |
| |
| EXPECT_TRUE(builder.StartNextServiceExploration()); |
| // Grabbing first service, to start Included Service and Characteristic |
| // discovery |
| ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0030, 0x003f)); |
| |
| builder.AddIncludedService(0x0031, SERVICE_4_UUID, 0x0040, 0x004f); |
| builder.AddIncludedService(0x0032, SERVICE_2_UUID, 0x0020, 0x002f); |
| |
| /* Secondary service exploration */ |
| EXPECT_TRUE(builder.StartNextServiceExploration()); |
| ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0020, 0x002f)); |
| |
| /* Secondary service exploration */ |
| EXPECT_TRUE(builder.StartNextServiceExploration()); |
| ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0040, 0x004f)); |
| |
| /* Back to primary service exploration */ |
| EXPECT_TRUE(builder.StartNextServiceExploration()); |
| ASSERT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0050, 0x005f)); |
| |
| Database result = builder.Build(); |
| |
| // verify that the returned database matches what was discovered |
| auto service = result.Services().begin(); |
| ASSERT_EQ(service->handle, 0x0001); |
| ASSERT_EQ(service->is_primary, true); |
| ASSERT_EQ(service->uuid, SERVICE_1_UUID); |
| |
| service++; |
| ASSERT_EQ(service->handle, 0x0020); |
| ASSERT_EQ(service->end_handle, 0x002f); |
| ASSERT_EQ(service->uuid, SERVICE_2_UUID); |
| ASSERT_EQ(service->is_primary, false); |
| |
| service++; |
| ASSERT_EQ(service->handle, 0x0030); |
| ASSERT_EQ(service->end_handle, 0x003f); |
| ASSERT_EQ(service->uuid, SERVICE_3_UUID); |
| ASSERT_EQ(service->is_primary, true); |
| ASSERT_EQ(service->included_services.size(), (size_t)2); |
| ASSERT_EQ(service->included_services[0].start_handle, 0x0040); |
| ASSERT_EQ(service->included_services[0].end_handle, 0x004f); |
| ASSERT_EQ(service->included_services[1].start_handle, 0x0020); |
| ASSERT_EQ(service->included_services[1].end_handle, 0x002f); |
| |
| service++; |
| ASSERT_EQ(service->handle, 0x0040); |
| ASSERT_EQ(service->uuid, SERVICE_4_UUID); |
| ASSERT_EQ(service->is_primary, false); |
| |
| service++; |
| ASSERT_EQ(service->handle, 0x0050); |
| ASSERT_EQ(service->uuid, SERVICE_5_UUID); |
| ASSERT_EQ(service->is_primary, true); |
| |
| service++; |
| ASSERT_EQ(service, result.Services().end()); |
| } |
| |
| } // namespace gatt |