diff options
author | armansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-03 02:25:23 +0000 |
---|---|---|
committer | armansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-03 02:25:23 +0000 |
commit | ce8c2a80fddc4866d88dfba43b8d4c39ba1b0063 (patch) | |
tree | b94dd6b80502cdfa77f39545bfb74f627997f03b | |
parent | f1a571eb319c7390f4ab6d2dfdb804fd142236c4 (diff) | |
download | chromium_src-ce8c2a80fddc4866d88dfba43b8d4c39ba1b0063.zip chromium_src-ce8c2a80fddc4866d88dfba43b8d4c39ba1b0063.tar.gz chromium_src-ce8c2a80fddc4866d88dfba43b8d4c39ba1b0063.tar.bz2 |
chrome.bluetoothLowEnergy: Implement getCharacteristics.
This CL implements the getCharacteristics method of the bluetoothLowEnergy API
and adds a mapping for Characteristic instance IDs to
BluetoothLowEnergyEventRouter.
BUG=265663
TEST=browser_tests --gtest_filter=BluetoothLowEnergyApiTest.*
Review URL: https://codereview.chromium.org/255053002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268009 0039d316-1c4b-4281-b951-d872f2087c98
9 files changed, 509 insertions, 8 deletions
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc index 972d395..cb637d4 100644 --- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc +++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_api.cc @@ -38,6 +38,35 @@ void DoWorkCallback(const base::Callback<bool()>& callback) { callback.Run(); } +// TODO(armansito): Remove this function once the described bug is fixed. +// (See crbug.com/368368). +// +// Converts an apibtle::Characteristic to a base::Value. This function is +// necessary, as json_schema_compiler::util::AddItemToList has no template +// specialization for user defined enums, which get treated as integers. This is +// because Characteristic contains a list of enum CharacteristicProperty. +scoped_ptr<base::DictionaryValue> CharacteristicToValue( + apibtle::Characteristic* from) { + // Copy the properties. Use Characteristic::ToValue to generate the result + // dictionary without the properties, to prevent json_schema_compiler from + // failing. + std::vector<apibtle::CharacteristicProperty> properties = from->properties; + from->properties.clear(); + scoped_ptr<base::DictionaryValue> to = from->ToValue(); + + // Manually set each property. + scoped_ptr<base::ListValue> property_list(new base::ListValue()); + for (std::vector<apibtle::CharacteristicProperty>::iterator iter = + properties.begin(); + iter != properties.end(); + ++iter) + property_list->Append(new base::StringValue(apibtle::ToString(*iter))); + + to->Set("properties", property_list.release()); + + return to.Pass(); +} + } // namespace namespace extensions { @@ -175,10 +204,48 @@ bool BluetoothLowEnergyGetCharacteristicFunction::DoWork() { } bool BluetoothLowEnergyGetCharacteristicsFunction::DoWork() { - // TODO(armansito): Implement. - SetError("Call not supported."); - SendResponse(false); - return false; + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + BluetoothLowEnergyEventRouter* event_router = + GetEventRouter(browser_context()); + + // The adapter must be initialized at this point, but return an error instead + // of asserting. + if (!event_router->HasAdapter()) { + SetError(kErrorAdapterNotInitialized); + SendResponse(false); + return false; + } + + scoped_ptr<apibtle::GetCharacteristics::Params> params( + apibtle::GetCharacteristics::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); + + std::string service_id = params->service_id; + + BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list; + if (!event_router->GetCharacteristics(service_id, &characteristic_list)) { + SetError( + base::StringPrintf(kErrorServiceNotFoundFormat, service_id.c_str())); + + SendResponse(false); + return false; + } + + // Manually construct the result instead of using + // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of + // enums correctly. + scoped_ptr<base::ListValue> result(new base::ListValue()); + for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter = + characteristic_list.begin(); + iter != characteristic_list.end(); + ++iter) + result->Append(CharacteristicToValue(iter->get()).release()); + + SetResult(result.release()); + SendResponse(true); + + return true; } bool BluetoothLowEnergyGetIncludedServicesFunction::DoWork() { diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc index fb1da70..3519ac8 100644 --- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc +++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc @@ -10,17 +10,21 @@ #include "chrome/browser/extensions/extension_test_message_listener.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/bluetooth/test/mock_bluetooth_device.h" +#include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h" #include "device/bluetooth/test/mock_bluetooth_gatt_service.h" #include "testing/gmock/include/gmock/gmock.h" using device::BluetoothUUID; using device::BluetoothAdapter; using device::BluetoothDevice; +using device::BluetoothGattCharacteristic; using device::BluetoothGattService; using device::MockBluetoothAdapter; using device::MockBluetoothDevice; +using device::MockBluetoothGattCharacteristic; using device::MockBluetoothGattService; using testing::Return; +using testing::ReturnRefOfCopy; using testing::_; namespace utils = extension_function_test_utils; @@ -32,9 +36,32 @@ const char kTestLeDeviceName[] = "Test LE Device"; const char kTestServiceId0[] = "service_id0"; const char kTestServiceUuid0[] = "1234"; + const char kTestServiceId1[] = "service_id1"; const char kTestServiceUuid1[] = "5678"; +const char kTestCharacteristicId0[] = "char_id0"; +const char kTestCharacteristicUuid0[] = "1211"; +const BluetoothGattCharacteristic::Properties kTestCharacteristicProperties0 = + BluetoothGattCharacteristic::kPropertyBroadcast | + BluetoothGattCharacteristic::kPropertyRead | + BluetoothGattCharacteristic::kPropertyWriteWithoutResponse | + BluetoothGattCharacteristic::kPropertyIndicate; +const uint8 kTestCharacteristicDefaultValue0[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + +const char kTestCharacteristicId1[] = "char_id1"; +const char kTestCharacteristicUuid1[] = "1212"; +const BluetoothGattCharacteristic::Properties kTestCharacteristicProperties1 = + BluetoothGattCharacteristic::kPropertyRead | + BluetoothGattCharacteristic::kPropertyWrite | + BluetoothGattCharacteristic::kPropertyNotify; +const uint8 kTestCharacteristicDefaultValue1[] = {0x06, 0x07, 0x08}; + +const char kTestCharacteristicId2[] = "char_id1"; +const char kTestCharacteristicUuid2[] = "1213"; +const BluetoothGattCharacteristic::Properties kTestCharacteristicProperties2 = + BluetoothGattCharacteristic::kPropertyNone; + class BluetoothLowEnergyApiTest : public ExtensionApiTest { public: BluetoothLowEnergyApiTest() {} @@ -79,6 +106,43 @@ class BluetoothLowEnergyApiTest : public ExtensionApiTest { BluetoothUUID(kTestServiceUuid1), false /* is_primary */, false /* is_local */)); + + // Assign characteristics some random properties and permissions. They don't + // need to reflect what the characteristic is actually capable of, since + // the JS API just passes values through from + // device::BluetoothGattCharacteristic. + std::vector<uint8> default_value; + chrc0_.reset(new testing::NiceMock<MockBluetoothGattCharacteristic>( + service0_.get(), + kTestCharacteristicId0, + BluetoothUUID(kTestCharacteristicUuid0), + false /* is_local */, + kTestCharacteristicProperties0, + BluetoothGattCharacteristic::kPermissionNone)); + default_value.assign(kTestCharacteristicDefaultValue0, + (kTestCharacteristicDefaultValue0 + + sizeof(kTestCharacteristicDefaultValue0))); + ON_CALL(*chrc0_, GetValue()).WillByDefault(ReturnRefOfCopy(default_value)); + + chrc1_.reset(new testing::NiceMock<MockBluetoothGattCharacteristic>( + service0_.get(), + kTestCharacteristicId1, + BluetoothUUID(kTestCharacteristicUuid1), + false /* is_local */, + kTestCharacteristicProperties1, + BluetoothGattCharacteristic::kPermissionNone)); + default_value.assign(kTestCharacteristicDefaultValue1, + (kTestCharacteristicDefaultValue1 + + sizeof(kTestCharacteristicDefaultValue1))); + ON_CALL(*chrc1_, GetValue()).WillByDefault(ReturnRefOfCopy(default_value)); + + chrc2_.reset(new testing::NiceMock<MockBluetoothGattCharacteristic>( + service1_.get(), + kTestCharacteristicId2, + BluetoothUUID(kTestCharacteristicUuid2), + false /* is_local */, + kTestCharacteristicProperties2, + BluetoothGattCharacteristic::kPermissionNone)); } protected: @@ -91,6 +155,9 @@ class BluetoothLowEnergyApiTest : public ExtensionApiTest { scoped_ptr<testing::NiceMock<MockBluetoothDevice> > device_; scoped_ptr<testing::NiceMock<MockBluetoothGattService> > service0_; scoped_ptr<testing::NiceMock<MockBluetoothGattService> > service1_; + scoped_ptr<testing::NiceMock<MockBluetoothGattCharacteristic> > chrc0_; + scoped_ptr<testing::NiceMock<MockBluetoothGattCharacteristic> > chrc1_; + scoped_ptr<testing::NiceMock<MockBluetoothGattCharacteristic> > chrc2_; private: scoped_refptr<extensions::Extension> empty_extension_; @@ -256,6 +323,41 @@ IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, GetIncludedServices) { listener.Reply("go"); listener.Reset(); + + EXPECT_TRUE(listener.WaitUntilSatisfied()); + + listener.Reply("go"); + + EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); + event_router()->GattServiceRemoved(device_.get(), service0_.get()); + event_router()->DeviceRemoved(mock_adapter_, device_.get()); +} + +IN_PROC_BROWSER_TEST_F(BluetoothLowEnergyApiTest, GetCharacteristics) { + ResultCatcher catcher; + catcher.RestrictToProfile(browser()->profile()); + + std::vector<BluetoothGattCharacteristic*> characteristics; + characteristics.push_back(chrc0_.get()); + characteristics.push_back(chrc1_.get()); + + event_router()->DeviceAdded(mock_adapter_, device_.get()); + event_router()->GattServiceAdded(device_.get(), service0_.get()); + + EXPECT_CALL(*mock_adapter_, GetDevice(_)).Times(3).WillRepeatedly( + Return(device_.get())); + EXPECT_CALL(*device_, GetGattService(kTestServiceId0)) + .Times(3) + .WillOnce(Return(static_cast<BluetoothGattService*>(NULL))) + .WillRepeatedly(Return(service0_.get())); + EXPECT_CALL(*service0_, GetCharacteristics()) + .Times(2) + .WillOnce(Return(std::vector<BluetoothGattCharacteristic*>())) + .WillOnce(Return(characteristics)); + + ExtensionTestMessageListener listener("ready", true); + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("bluetooth_low_energy/get_characteristics"))); EXPECT_TRUE(listener.WaitUntilSatisfied()); listener.Reply("go"); diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc index d9d96c4..c505780 100644 --- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc +++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc @@ -9,6 +9,7 @@ #include "base/values.h" #include "content/public/browser/browser_thread.h" #include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/bluetooth_gatt_characteristic.h" #include "extensions/browser/event_router.h" using content::BrowserThread; @@ -39,6 +40,64 @@ void PopulateService(const BluetoothGattService* service, new std::string(service->GetDevice()->GetAddress())); } +void PopulateCharacteristicProperties( + BluetoothGattCharacteristic::Properties properties, + std::vector<apibtle::CharacteristicProperty>* api_properties) { + DCHECK(api_properties && api_properties->empty()); + + if (properties == BluetoothGattCharacteristic::kPropertyNone) + return; + + if (properties & BluetoothGattCharacteristic::kPropertyBroadcast) + api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST); + if (properties & BluetoothGattCharacteristic::kPropertyRead) + api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ); + if (properties & BluetoothGattCharacteristic::kPropertyWriteWithoutResponse) { + api_properties->push_back( + apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE); + } + if (properties & BluetoothGattCharacteristic::kPropertyWrite) + api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE); + if (properties & BluetoothGattCharacteristic::kPropertyNotify) + api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY); + if (properties & BluetoothGattCharacteristic::kPropertyIndicate) + api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE); + if (properties & + BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) { + api_properties->push_back( + apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES); + } + if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) { + api_properties->push_back( + apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES); + } + if (properties & BluetoothGattCharacteristic::kPropertyReliableWrite) + api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE); + if (properties & BluetoothGattCharacteristic::kPropertyWriteableAuxiliaries) { + api_properties->push_back( + apibtle::CHARACTERISTIC_PROPERTY_WRITEABLEAUXILIARIES); + } +} + +void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic, + apibtle::Characteristic* out) { + DCHECK(out); + + out->uuid = characteristic->GetUUID().canonical_value(); + out->is_local = characteristic->IsLocal(); + out->instance_id.reset(new std::string(characteristic->GetIdentifier())); + + PopulateService(characteristic->GetService(), &out->service); + PopulateCharacteristicProperties(characteristic->GetProperties(), + &out->properties); + + const std::vector<uint8>& value = characteristic->GetValue(); + if (value.empty()) + return; + + out->value.reset(new std::string(value.begin(), value.end())); +} + } // namespace namespace extensions { @@ -217,6 +276,42 @@ bool BluetoothLowEnergyEventRouter::GetIncludedServices( return true; } +bool BluetoothLowEnergyEventRouter::GetCharacteristics( + const std::string& instance_id, + CharacteristicList* out_characteristics) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(out_characteristics); + if (!adapter_) { + VLOG(1) << "BlutoothAdapter not ready."; + return false; + } + + BluetoothGattService* service = FindServiceById(instance_id); + if (!service) { + VLOG(1) << "Service not found: " << instance_id; + return false; + } + + out_characteristics->clear(); + + const std::vector<BluetoothGattCharacteristic*>& characteristics = + service->GetCharacteristics(); + for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter = + characteristics.begin(); + iter != characteristics.end(); + ++iter) { + // Populate an API characteristic and add it to the return value. + const BluetoothGattCharacteristic* characteristic = *iter; + linked_ptr<apibtle::Characteristic> api_characteristic( + new apibtle::Characteristic()); + PopulateCharacteristic(characteristic, api_characteristic.get()); + + out_characteristics->push_back(api_characteristic); + } + + return true; +} + void BluetoothLowEnergyEventRouter::SetAdapterForTesting( device::BluetoothAdapter* adapter) { adapter_ = adapter; @@ -324,13 +419,33 @@ void BluetoothLowEnergyEventRouter::GattServiceChanged( void BluetoothLowEnergyEventRouter::GattCharacteristicAdded( BluetoothGattService* service, BluetoothGattCharacteristic* characteristic) { - // TODO(armansito): Implement. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier(); + + DCHECK(chrc_ids_to_objects_.find(characteristic->GetIdentifier()) == + chrc_ids_to_objects_.end()); + + GattObjectData data; + data.device_address = service->GetDevice()->GetAddress(); + data.service_id = service->GetIdentifier(); + data.characteristic_id = characteristic->GetIdentifier(); + chrc_ids_to_objects_[characteristic->GetIdentifier()] = data; } void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved( BluetoothGattService* service, BluetoothGattCharacteristic* characteristic) { - // TODO(armansito): Implement. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier(); + + DCHECK(chrc_ids_to_objects_.find(characteristic->GetIdentifier()) != + chrc_ids_to_objects_.end()); + DCHECK(service->GetDevice()->GetAddress() == + chrc_ids_to_objects_[characteristic->GetIdentifier()].device_address); + DCHECK(service->GetIdentifier() == + chrc_ids_to_objects_[characteristic->GetIdentifier()].service_id); + + chrc_ids_to_objects_.erase(characteristic->GetIdentifier()); } void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged( @@ -359,6 +474,7 @@ void BluetoothLowEnergyEventRouter::OnGetAdapter( } void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() { + // Devices BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); for (BluetoothAdapter::DeviceList::iterator iter = devices.begin(); iter != devices.end(); @@ -367,6 +483,7 @@ void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() { device->AddObserver(this); observed_devices_.insert(device->GetAddress()); + // Services std::vector<BluetoothGattService*> services = device->GetGattServices(); for (std::vector<BluetoothGattService*>::iterator siter = services.begin(); siter != services.end(); @@ -380,7 +497,23 @@ void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() { service_data.service_id = service->GetIdentifier(); service_ids_to_objects_[service_data.service_id] = service_data; - // TODO(armansito): Initialize mapping for characteristics & descriptors. + // Characteristics + std::vector<BluetoothGattCharacteristic*> characteristics = + service->GetCharacteristics(); + for (std::vector<BluetoothGattCharacteristic*>::iterator citer = + characteristics.begin(); + citer != characteristics.end(); + ++citer) { + BluetoothGattCharacteristic* characteristic = *citer; + GattObjectData characteristic_data; + characteristic_data.device_address = device->GetAddress(); + characteristic_data.service_id = service->GetIdentifier(); + characteristic_data.characteristic_id = characteristic->GetIdentifier(); + chrc_ids_to_objects_[characteristic_data.characteristic_id] = + characteristic_data; + + // TODO(armansito): Initialize mapping for descriptors. + } } } } diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h index 82e20ad..6ad37262 100644 --- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h +++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h @@ -61,7 +61,7 @@ class BluetoothLowEnergyEventRouter // with the Bluetooth device with address |device_address| in |out_services|. // Returns false, if no device with the given address is known. If the device // is found but it has no GATT services, then returns true and leaves - // |out_services| as empty. Returns true, on success. |out_services| must not + // |out_services| empty. Returns true, on success. |out_services| must not // be NULL. If it is non-empty, then its contents will be cleared. typedef std::vector<linked_ptr<api::bluetooth_low_energy::Service> > ServiceList; @@ -83,6 +83,18 @@ class BluetoothLowEnergyEventRouter bool GetIncludedServices(const std::string& instance_id, ServiceList* out_services) const; + // Returns the list of api::bluetooth_low_energy::Characteristic objects + // associated with the GATT service with instance ID |instance_id| in + // |out_characteristics|. Returns false, if no service with the given instance + // ID is known. If the service is found but it has no characteristics, then + // returns true and leaves |out_characteristics| empty. Returns true on + // success. |out_characteristics| must not be NULL and if it is non-empty, + // then its contents will be cleared. + typedef std::vector<linked_ptr<api::bluetooth_low_energy::Characteristic> > + CharacteristicList; + bool GetCharacteristics(const std::string& instance_id, + CharacteristicList* out_characteristics) const; + // Initializes the adapter for testing. Used by unit tests only. void SetAdapterForTesting(device::BluetoothAdapter* adapter); @@ -153,6 +165,7 @@ class BluetoothLowEnergyEventRouter // device::BluetoothGattService that owns the characteristic. typedef std::map<std::string, GattObjectData> InstanceIdToObjectDataMap; InstanceIdToObjectDataMap service_ids_to_objects_; + InstanceIdToObjectDataMap chrc_ids_to_objects_; // Sets of BluetoothDevice and BluetoothGattService objects that are being // observed, used to remove the BluetoothLowEnergyEventRouter as an observer diff --git a/chrome/test/data/extensions/api_test/bluetooth_low_energy/get_characteristics/manifest.json b/chrome/test/data/extensions/api_test/bluetooth_low_energy/get_characteristics/manifest.json new file mode 100644 index 0000000..b6ec89b --- /dev/null +++ b/chrome/test/data/extensions/api_test/bluetooth_low_energy/get_characteristics/manifest.json @@ -0,0 +1,11 @@ +{ + "manifest_version": 2, + "name": "Test the Bluetooth Low Energy getCharacteristics API", + "version": "1.0", + "app": { + "background": { + "scripts": ["runtest.js"] + } + }, + "bluetooth": {} +} diff --git a/chrome/test/data/extensions/api_test/bluetooth_low_energy/get_characteristics/runtest.js b/chrome/test/data/extensions/api_test/bluetooth_low_energy/get_characteristics/runtest.js new file mode 100644 index 0000000..9e16b4b --- /dev/null +++ b/chrome/test/data/extensions/api_test/bluetooth_low_energy/get_characteristics/runtest.js @@ -0,0 +1,81 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function testGetCharacteristics() { + chrome.test.assertEq(2, chrcs.length); + + chrome.test.assertEq('char_id0', chrcs[0].instanceId), + chrome.test.assertEq('00001211-0000-1000-8000-00805f9b34fb', chrcs[0].uuid); + chrome.test.assertEq(false, chrcs[0].isLocal); + chrome.test.assertEq(serviceId, chrcs[0].service.instanceId); + chrome.test.assertEq(4, chrcs[0].properties.length); + chrome.test.assertTrue(chrcs[0].properties.indexOf('broadcast') > -1, + '\'broadcast\' not in chrcs[0].properties'); + chrome.test.assertTrue(chrcs[0].properties.indexOf('read') > -1, + '\'read\' not in chrcs[0].properties'); + chrome.test.assertTrue(chrcs[0].properties.indexOf('indicate') > -1, + '\'indicate\' not in chrcs[0].properties'); + chrome.test.assertTrue( + chrcs[0].properties.indexOf('writeWithoutResponse') > -1, + '\'writeWithoutResponse\' not in chrcs[0].properties'); + + var valueBytes = new Uint8Array(chrcs[0].value); + chrome.test.assertEq(5, chrcs[0].value.byteLength); + chrome.test.assertEq(0x01, valueBytes[0]); + chrome.test.assertEq(0x02, valueBytes[1]); + chrome.test.assertEq(0x03, valueBytes[2]); + chrome.test.assertEq(0x04, valueBytes[3]); + chrome.test.assertEq(0x05, valueBytes[4]); + + chrome.test.assertEq('char_id1', chrcs[1].instanceId), + chrome.test.assertEq('00001212-0000-1000-8000-00805f9b34fb', chrcs[1].uuid); + chrome.test.assertEq(false, chrcs[1].isLocal); + chrome.test.assertEq(serviceId, chrcs[1].service.instanceId); + chrome.test.assertEq(3, chrcs[1].properties.length); + chrome.test.assertTrue(chrcs[1].properties.indexOf('read') > -1, + '\'read\' not in chrcs[1].properties'); + chrome.test.assertTrue(chrcs[1].properties.indexOf('write') > -1, + '\'write\' not in chrcs[1].properties'); + chrome.test.assertTrue(chrcs[1].properties.indexOf('notify') > -1, + '\'notify\' not in chrcs[1].properties'); + + valueBytes = new Uint8Array(chrcs[1].value); + chrome.test.assertEq(3, chrcs[1].value.byteLength); + chrome.test.assertEq(0x06, valueBytes[0]); + chrome.test.assertEq(0x07, valueBytes[1]); + chrome.test.assertEq(0x08, valueBytes[2]); + + chrome.test.succeed(); +} + +var serviceId = 'service_id0'; +var chrcs = null; + +function failOnError() { + if (chrome.runtime.lastError) { + chrome.test.fail(chrome.runtime.lastError.message); + } +} + +chrome.bluetoothLowEnergy.getCharacteristics(serviceId, function (result) { + if (result || !chrome.runtime.lastError) { + chrome.test.fail('getCharacteristics should have failed.'); + } + + chrome.bluetoothLowEnergy.getCharacteristics(serviceId, function (result) { + failOnError(); + if (!result || result.length != 0) { + chrome.test.fail('Characteristics should be empty.'); + } + + chrome.bluetoothLowEnergy.getCharacteristics(serviceId, function (result) { + failOnError(); + chrcs = result; + + chrome.test.sendMessage('ready', function (message) { + chrome.test.runTests([testGetCharacteristics]); + }); + }); + }); +}); diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp index deb7d26a..ec06dec 100644 --- a/device/bluetooth/bluetooth.gyp +++ b/device/bluetooth/bluetooth.gyp @@ -136,6 +136,8 @@ 'test/mock_bluetooth_device.h', 'test/mock_bluetooth_discovery_session.cc', 'test/mock_bluetooth_discovery_session.h', + 'test/mock_bluetooth_gatt_characteristic.cc', + 'test/mock_bluetooth_gatt_characteristic.h', 'test/mock_bluetooth_gatt_service.cc', 'test/mock_bluetooth_gatt_service.h', 'test/mock_bluetooth_profile.cc', diff --git a/device/bluetooth/test/mock_bluetooth_gatt_characteristic.cc b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.cc new file mode 100644 index 0000000..5cc4da3 --- /dev/null +++ b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.cc @@ -0,0 +1,37 @@ +// Copyright 2014 The Chromium 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 "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h" + +#include "device/bluetooth/test/mock_bluetooth_gatt_service.h" + +using testing::Return; +using testing::ReturnRefOfCopy; +using testing::_; + +namespace device { + +MockBluetoothGattCharacteristic::MockBluetoothGattCharacteristic( + MockBluetoothGattService* service, + const std::string& identifier, + const BluetoothUUID& uuid, + bool is_local, + Properties properties, + Permissions permissions) { + ON_CALL(*this, GetIdentifier()).WillByDefault(Return(identifier)); + ON_CALL(*this, GetUUID()).WillByDefault(Return(uuid)); + ON_CALL(*this, IsLocal()).WillByDefault(Return(is_local)); + ON_CALL(*this, GetValue()) + .WillByDefault(ReturnRefOfCopy(std::vector<uint8>())); + ON_CALL(*this, GetService()).WillByDefault(Return(service)); + ON_CALL(*this, GetProperties()).WillByDefault(Return(properties)); + ON_CALL(*this, GetPermissions()).WillByDefault(Return(permissions)); + ON_CALL(*this, GetDescriptors()) + .WillByDefault(Return(std::vector<BluetoothGattDescriptor*>())); +} + +MockBluetoothGattCharacteristic::~MockBluetoothGattCharacteristic() { +} + +} // namespace device diff --git a/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h new file mode 100644 index 0000000..6619543 --- /dev/null +++ b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h @@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_GATT_CHARACTERISTIC_H_ +#define DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_GATT_CHARACTERISTIC_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "device/bluetooth/bluetooth_gatt_characteristic.h" +#include "device/bluetooth/bluetooth_uuid.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace device { + +class BluetoothGattDescriptor; +class BluetoothGattService; +class MockBluetoothGattService; + +class MockBluetoothGattCharacteristic : public BluetoothGattCharacteristic { + public: + MockBluetoothGattCharacteristic(MockBluetoothGattService* service, + const std::string& identifier, + const BluetoothUUID& uuid, + bool is_local, + Properties properties, + Permissions permissions); + virtual ~MockBluetoothGattCharacteristic(); + + MOCK_CONST_METHOD0(GetIdentifier, std::string()); + MOCK_CONST_METHOD0(GetUUID, BluetoothUUID()); + MOCK_CONST_METHOD0(IsLocal, bool()); + MOCK_CONST_METHOD0(GetValue, const std::vector<uint8>&()); + MOCK_CONST_METHOD0(GetService, BluetoothGattService*()); + MOCK_CONST_METHOD0(GetProperties, Properties()); + MOCK_CONST_METHOD0(GetPermissions, Permissions()); + MOCK_CONST_METHOD0(GetDescriptors, std::vector<BluetoothGattDescriptor*>()); + MOCK_METHOD1(AddDescriptor, bool(BluetoothGattDescriptor*)); + MOCK_METHOD1(UpdateValue, bool(const std::vector<uint8>&)); + MOCK_METHOD2(ReadRemoteCharacteristic, + void(const ValueCallback&, const ErrorCallback&)); + MOCK_METHOD3(WriteRemoteCharacteristic, + void(const std::vector<uint8>&, + const base::Closure&, + const ErrorCallback&)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockBluetoothGattCharacteristic); +}; + +} // namespace device + +#endif // DEVICE_BLUETOOTH_TEST_MOCK_BLUETOOTH_GATT_CHARACTERISTIC_H_ |