bluetooth_adapter_mac_unittest.mm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/bluetooth/bluetooth_adapter_mac.h"
  5. #include "base/memory/raw_ptr.h"
  6. #import <Foundation/Foundation.h>
  7. #include <memory>
  8. #include "base/bind.h"
  9. #include "base/files/file_path.h"
  10. #include "base/files/file_util.h"
  11. #include "base/files/scoped_temp_dir.h"
  12. #include "base/memory/ptr_util.h"
  13. #include "base/memory/ref_counted.h"
  14. #include "base/task/sequenced_task_runner.h"
  15. #include "base/test/bind.h"
  16. #include "base/test/task_environment.h"
  17. #include "base/test/test_simple_task_runner.h"
  18. #include "build/build_config.h"
  19. #include "device/bluetooth/bluetooth_adapter.h"
  20. #include "device/bluetooth/bluetooth_common.h"
  21. #include "device/bluetooth/bluetooth_discovery_session.h"
  22. #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
  23. #import "device/bluetooth/bluetooth_low_energy_device_mac.h"
  24. #include "device/bluetooth/bluetooth_low_energy_device_watcher_mac.h"
  25. #import "device/bluetooth/test/mock_bluetooth_cbperipheral_mac.h"
  26. #import "device/bluetooth/test/mock_bluetooth_central_manager_mac.h"
  27. #import "device/bluetooth/test/test_bluetooth_adapter_observer.h"
  28. #include "testing/gtest/include/gtest/gtest.h"
  29. #if BUILDFLAG(IS_IOS)
  30. #import <CoreBluetooth/CoreBluetooth.h>
  31. #else // !BUILDFLAG(IS_IOS)
  32. #import <IOBluetooth/IOBluetooth.h>
  33. #endif // BUILDFLAG(IS_IOS)
  34. namespace {
  35. const char kTestPropertyListFileName[] = "test_property_list_file.plist";
  36. // |kTestHashAddress| is the hash corresponding to identifier |kTestNSUUID|.
  37. const char kTestNSUUID[] = "00000000-1111-2222-3333-444444444444";
  38. const char kTestHashAddress[] = "D1:6F:E3:22:FD:5B";
  39. const int kTestRssi = 0;
  40. NSDictionary* CreateTestPropertyListData() {
  41. return @{
  42. @"CoreBluetoothCache" : @{
  43. @"00000000-1111-2222-3333-444444444444" : @{
  44. @"DeviceAddress" : @"22-22-22-22-22-22",
  45. @"DeviceAddressType" : @1,
  46. @"ServiceChangedHandle" : @3,
  47. @"ServiceChangeSubscribed" : @0,
  48. @"ServiceDiscoveryComplete" : @0
  49. }
  50. }
  51. };
  52. }
  53. bool IsTestDeviceSystemPaired(const std::string& address) {
  54. return true;
  55. }
  56. } // namespace
  57. namespace device {
  58. class BluetoothAdapterMacTest : public testing::Test {
  59. public:
  60. class FakeBluetoothLowEnergyDeviceWatcherMac
  61. : public BluetoothLowEnergyDeviceWatcherMac {
  62. public:
  63. FakeBluetoothLowEnergyDeviceWatcherMac(
  64. scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner,
  65. LowEnergyDeviceListUpdatedCallback callback)
  66. : BluetoothLowEnergyDeviceWatcherMac(ui_thread_task_runner, callback),
  67. weak_ptr_factory_(this) {}
  68. void SimulatePropertyListFileChanged(
  69. const base::FilePath& path,
  70. const std::string& changed_file_content) {
  71. auto expected_file_size = changed_file_content.length();
  72. ASSERT_EQ(static_cast<int>(expected_file_size),
  73. base::WriteFile(path, changed_file_content.data(),
  74. expected_file_size));
  75. OnPropertyListFileChangedOnFileThread(path, false /* error */);
  76. }
  77. private:
  78. ~FakeBluetoothLowEnergyDeviceWatcherMac() override = default;
  79. void Init() override { ReadBluetoothPropertyListFile(); }
  80. void ReadBluetoothPropertyListFile() override {
  81. low_energy_device_list_updated_callback().Run(
  82. ParseBluetoothDevicePropertyListData(CreateTestPropertyListData()));
  83. }
  84. base::WeakPtrFactory<FakeBluetoothLowEnergyDeviceWatcherMac>
  85. weak_ptr_factory_;
  86. };
  87. BluetoothAdapterMacTest()
  88. : ui_task_runner_(new base::TestSimpleTaskRunner()),
  89. adapter_(new BluetoothAdapterMac()),
  90. adapter_mac_(static_cast<BluetoothAdapterMac*>(adapter_.get())),
  91. observer_(adapter_),
  92. callback_count_(0),
  93. error_callback_count_(0) {
  94. adapter_mac_->SetGetDevicePairedStatusCallbackForTesting(
  95. base::BindRepeating(&IsTestDeviceSystemPaired));
  96. adapter_mac_->InitForTest(ui_task_runner_);
  97. fake_low_energy_device_watcher_ =
  98. base::MakeRefCounted<FakeBluetoothLowEnergyDeviceWatcherMac>(
  99. ui_task_runner_,
  100. base::BindRepeating(
  101. &BluetoothAdapterMac::UpdateKnownLowEnergyDevices,
  102. adapter_mac_->weak_ptr_factory_.GetWeakPtr()));
  103. }
  104. void SetUp() override {
  105. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  106. test_property_list_file_path_ =
  107. temp_dir_.GetPath().AppendASCII(kTestPropertyListFileName);
  108. }
  109. void TearDown() override { task_environment_.RunUntilIdle(); }
  110. // Helper methods for setup and access to BluetoothAdapterMacTest's members.
  111. void PollAdapter() { adapter_mac_->PollAdapter(); }
  112. void SetHostControllerPowerFunction(bool powered) {
  113. adapter_mac_->SetHostControllerStateFunctionForTesting(
  114. base::BindLambdaForTesting([powered] {
  115. BluetoothAdapterMac::HostControllerState state;
  116. state.classic_powered = powered;
  117. return state;
  118. }));
  119. }
  120. void LowEnergyDeviceUpdated(CBPeripheral* peripheral,
  121. NSDictionary* advertisement_data,
  122. int rssi) {
  123. adapter_mac_->LowEnergyDeviceUpdated(peripheral, advertisement_data, rssi);
  124. }
  125. BluetoothDevice* GetDevice(const std::string& address) {
  126. return adapter_->GetDevice(address);
  127. }
  128. CBPeripheral* CreateMockPeripheral(const char* identifier) {
  129. base::scoped_nsobject<MockCBPeripheral> mock_peripheral(
  130. [[MockCBPeripheral alloc] initWithUTF8StringIdentifier:identifier]);
  131. return [[mock_peripheral peripheral] retain];
  132. }
  133. NSDictionary* AdvertisementData() {
  134. NSDictionary* advertisement_data = @{
  135. CBAdvertisementDataIsConnectable : @(YES),
  136. CBAdvertisementDataServiceDataKey : @{},
  137. };
  138. return [advertisement_data retain];
  139. }
  140. std::string GetHashAddress(CBPeripheral* peripheral) {
  141. return BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress(peripheral);
  142. }
  143. int NumDevices() { return adapter_mac_->devices_.size(); }
  144. bool DevicePresent(CBPeripheral* peripheral) {
  145. BluetoothDevice* device = adapter_mac_->GetDevice(
  146. BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress(peripheral));
  147. return (device != NULL);
  148. }
  149. bool SetMockCentralManager(CBManagerState desired_state) {
  150. mock_central_manager_.reset([[MockCentralManager alloc] init]);
  151. [mock_central_manager_ setState:desired_state];
  152. CBCentralManager* centralManager =
  153. static_cast<CBCentralManager*>(mock_central_manager_.get());
  154. adapter_mac_->SetCentralManagerForTesting(centralManager);
  155. return true;
  156. }
  157. void OnStartDiscoverySessionSuccess(
  158. std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) {
  159. active_sessions_.push_back(std::move(discovery_session));
  160. Callback();
  161. }
  162. int NumDiscoverySessions() { return adapter_mac_->NumDiscoverySessions(); }
  163. void SetFakeLowEnergyDeviceWatcher() {
  164. adapter_mac_->SetLowEnergyDeviceWatcherForTesting(
  165. fake_low_energy_device_watcher_);
  166. }
  167. // Generic callbacks.
  168. void Callback() { ++callback_count_; }
  169. void ErrorCallback() { ++error_callback_count_; }
  170. void DiscoveryErrorCallback(UMABluetoothDiscoverySessionOutcome) {
  171. ++error_callback_count_;
  172. }
  173. protected:
  174. base::test::TaskEnvironment task_environment_;
  175. scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
  176. scoped_refptr<BluetoothAdapter> adapter_;
  177. raw_ptr<BluetoothAdapterMac> adapter_mac_;
  178. scoped_refptr<FakeBluetoothLowEnergyDeviceWatcherMac>
  179. fake_low_energy_device_watcher_;
  180. TestBluetoothAdapterObserver observer_;
  181. std::vector<std::unique_ptr<BluetoothDiscoverySession>> active_sessions_;
  182. // Owned by |adapter_mac_|.
  183. base::scoped_nsobject<MockCentralManager> mock_central_manager_;
  184. int callback_count_;
  185. int error_callback_count_;
  186. base::ScopedTempDir temp_dir_;
  187. base::FilePath test_property_list_file_path_;
  188. };
  189. TEST_F(BluetoothAdapterMacTest, Poll) {
  190. PollAdapter();
  191. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  192. }
  193. TEST_F(BluetoothAdapterMacTest, PollAndChangePower) {
  194. // By default the adapter is powered off, check that this expectation matches
  195. // reality.
  196. EXPECT_FALSE(adapter_mac_->IsPowered());
  197. EXPECT_EQ(0, observer_.powered_changed_count());
  198. SetHostControllerPowerFunction(true);
  199. PollAdapter();
  200. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  201. ui_task_runner_->RunPendingTasks();
  202. EXPECT_EQ(1, observer_.powered_changed_count());
  203. EXPECT_TRUE(observer_.last_powered());
  204. EXPECT_TRUE(adapter_mac_->IsPowered());
  205. SetHostControllerPowerFunction(false);
  206. PollAdapter();
  207. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  208. ui_task_runner_->RunPendingTasks();
  209. EXPECT_EQ(2, observer_.powered_changed_count());
  210. EXPECT_FALSE(observer_.last_powered());
  211. EXPECT_FALSE(adapter_mac_->IsPowered());
  212. }
  213. TEST_F(BluetoothAdapterMacTest, AddDiscoverySessionWithLowEnergyFilter) {
  214. if (!SetMockCentralManager(CBManagerStatePoweredOn))
  215. return;
  216. EXPECT_EQ(0, [mock_central_manager_ scanForPeripheralsCallCount]);
  217. EXPECT_EQ(0, NumDiscoverySessions());
  218. std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(
  219. new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE));
  220. adapter_mac_->StartDiscoverySessionWithFilter(
  221. std::move(discovery_filter),
  222. /*client_name=*/std::string(),
  223. base::BindOnce(&BluetoothAdapterMacTest::OnStartDiscoverySessionSuccess,
  224. base::Unretained(this)),
  225. base::BindOnce(&BluetoothAdapterMacTest::ErrorCallback,
  226. base::Unretained(this)));
  227. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  228. ui_task_runner_->RunPendingTasks();
  229. EXPECT_EQ(1, callback_count_);
  230. EXPECT_EQ(0, error_callback_count_);
  231. EXPECT_EQ(1, NumDiscoverySessions());
  232. // Check that adding a discovery session resulted in
  233. // scanForPeripheralsWithServices being called on the Central Manager.
  234. EXPECT_EQ(1, [mock_central_manager_ scanForPeripheralsCallCount]);
  235. }
  236. // TODO(krstnmnlsn): Test changing the filter when adding the second discovery
  237. // session (once we have that ability).
  238. TEST_F(BluetoothAdapterMacTest, AddSecondDiscoverySessionWithLowEnergyFilter) {
  239. if (!SetMockCentralManager(CBManagerStatePoweredOn))
  240. return;
  241. std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(
  242. new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE));
  243. std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(
  244. new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE));
  245. // Adding uuid to first discovery session so that there is a change to be made
  246. // when starting the second session.
  247. BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
  248. device_filter.uuids.insert(device::BluetoothUUID("1000"));
  249. discovery_filter->AddDeviceFilter(device_filter);
  250. adapter_mac_->StartDiscoverySessionWithFilter(
  251. std::move(discovery_filter),
  252. /*client_name=*/std::string(),
  253. base::BindOnce(&BluetoothAdapterMacTest::OnStartDiscoverySessionSuccess,
  254. base::Unretained(this)),
  255. base::BindOnce(&BluetoothAdapterMacTest::ErrorCallback,
  256. base::Unretained(this)));
  257. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  258. ui_task_runner_->RunPendingTasks();
  259. EXPECT_EQ(1, callback_count_);
  260. EXPECT_EQ(0, error_callback_count_);
  261. EXPECT_EQ(1, NumDiscoverySessions());
  262. // We replaced the success callback handed to AddDiscoverySession, so
  263. // |adapter_mac_| should remain in a discovering state indefinitely.
  264. EXPECT_TRUE(adapter_mac_->IsDiscovering());
  265. adapter_mac_->StartDiscoverySessionWithFilter(
  266. std::move(discovery_filter2),
  267. /*client_name=*/std::string(),
  268. base::BindOnce(&BluetoothAdapterMacTest::OnStartDiscoverySessionSuccess,
  269. base::Unretained(this)),
  270. base::BindOnce(&BluetoothAdapterMacTest::ErrorCallback,
  271. base::Unretained(this)));
  272. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  273. ui_task_runner_->RunPendingTasks();
  274. EXPECT_EQ(2, [mock_central_manager_ scanForPeripheralsCallCount]);
  275. EXPECT_EQ(2, callback_count_);
  276. EXPECT_EQ(0, error_callback_count_);
  277. EXPECT_EQ(2, NumDiscoverySessions());
  278. }
  279. TEST_F(BluetoothAdapterMacTest, RemoveDiscoverySessionWithLowEnergyFilter) {
  280. if (!SetMockCentralManager(CBManagerStatePoweredOn))
  281. return;
  282. EXPECT_EQ(0, [mock_central_manager_ scanForPeripheralsCallCount]);
  283. std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(
  284. new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE));
  285. adapter_mac_->StartDiscoverySessionWithFilter(
  286. std::move(discovery_filter),
  287. /*client_name=*/std::string(),
  288. base::BindOnce(&BluetoothAdapterMacTest::OnStartDiscoverySessionSuccess,
  289. base::Unretained(this)),
  290. base::BindOnce(&BluetoothAdapterMacTest::ErrorCallback,
  291. base::Unretained(this)));
  292. EXPECT_TRUE(ui_task_runner_->HasPendingTask());
  293. ui_task_runner_->RunPendingTasks();
  294. EXPECT_EQ(1, callback_count_);
  295. EXPECT_EQ(0, error_callback_count_);
  296. EXPECT_EQ(1, NumDiscoverySessions());
  297. EXPECT_EQ(0, [mock_central_manager_ stopScanCallCount]);
  298. active_sessions_[0]->Stop(
  299. base::BindOnce(&BluetoothAdapterMacTest::Callback,
  300. base::Unretained(this)),
  301. base::BindOnce(&BluetoothAdapterMacTest::ErrorCallback,
  302. base::Unretained(this)));
  303. EXPECT_EQ(2, callback_count_);
  304. EXPECT_EQ(0, error_callback_count_);
  305. EXPECT_EQ(0, NumDiscoverySessions());
  306. // Check that removing the discovery session resulted in stopScan being called
  307. // on the Central Manager.
  308. EXPECT_EQ(1, [mock_central_manager_ stopScanCallCount]);
  309. }
  310. TEST_F(BluetoothAdapterMacTest, CheckGetPeripheralHashAddress) {
  311. if (!SetMockCentralManager(CBManagerStatePoweredOn))
  312. return;
  313. base::scoped_nsobject<CBPeripheral> mock_peripheral(
  314. CreateMockPeripheral(kTestNSUUID));
  315. if (!mock_peripheral)
  316. return;
  317. EXPECT_EQ(kTestHashAddress, GetHashAddress(mock_peripheral));
  318. }
  319. TEST_F(BluetoothAdapterMacTest, LowEnergyDeviceUpdatedNewDevice) {
  320. if (!SetMockCentralManager(CBManagerStatePoweredOn))
  321. return;
  322. base::scoped_nsobject<CBPeripheral> mock_peripheral(
  323. CreateMockPeripheral(kTestNSUUID));
  324. if (!mock_peripheral)
  325. return;
  326. base::scoped_nsobject<NSDictionary> advertisement_data(AdvertisementData());
  327. EXPECT_EQ(0, NumDevices());
  328. EXPECT_FALSE(DevicePresent(mock_peripheral));
  329. LowEnergyDeviceUpdated(mock_peripheral, advertisement_data, kTestRssi);
  330. EXPECT_EQ(1, NumDevices());
  331. EXPECT_TRUE(DevicePresent(mock_peripheral));
  332. }
  333. TEST_F(BluetoothAdapterMacTest, GetSystemPairedLowEnergyDevice) {
  334. SetFakeLowEnergyDeviceWatcher();
  335. ui_task_runner_->RunUntilIdle();
  336. EXPECT_TRUE(
  337. adapter_mac_->IsBluetoothLowEnergyDeviceSystemPaired(kTestNSUUID));
  338. }
  339. TEST_F(BluetoothAdapterMacTest, GetNewlyPairedLowEnergyDevice) {
  340. constexpr char kPropertyListFileContentWithAddedDevice[] =
  341. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  342. "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
  343. "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
  344. "<plist version=\"1.0\">"
  345. "<dict>"
  346. " <key>CoreBluetoothCache</key>"
  347. " <dict> "
  348. " <key>E7F8589A-A7D9-4B94-9A08-D89076A159F4</key>"
  349. " <dict> "
  350. " <key>DeviceAddress</key>"
  351. " <string>11-11-11-11-11-11</string>"
  352. " <key>DeviceAddressType</key>"
  353. " <integer>1</integer>"
  354. " <key>ServiceChangedHandle</key>"
  355. " <integer>3</integer>"
  356. " <key>ServiceChangeSubscribed</key>"
  357. " <integer>0</integer>"
  358. " <key>ServiceDiscoveryComplete</key>"
  359. " <integer>0</integer>"
  360. " </dict>"
  361. " <key>00000000-1111-2222-3333-444444444444</key>"
  362. " <dict> "
  363. " <key>DeviceAddress</key>"
  364. " <string>22-22-22-22-22-22</string>"
  365. " <key>DeviceAddressType</key>"
  366. " <integer>1</integer>"
  367. " <key>ServiceChangedHandle</key>"
  368. " <integer>3</integer>"
  369. " <key>ServiceChangeSubscribed</key>"
  370. " <integer>0</integer>"
  371. " <key>ServiceDiscoveryComplete</key>"
  372. " <integer>0</integer>"
  373. " </dict>"
  374. " </dict>"
  375. "</dict>"
  376. "</plist>";
  377. const char kTestAddedDeviceNSUUID[] = "E7F8589A-A7D9-4B94-9A08-D89076A159F4";
  378. ASSERT_TRUE(SetMockCentralManager(CBManagerStatePoweredOn));
  379. base::scoped_nsobject<CBPeripheral> mock_peripheral_one(
  380. CreateMockPeripheral(kTestNSUUID));
  381. ASSERT_TRUE(mock_peripheral_one);
  382. LowEnergyDeviceUpdated(
  383. mock_peripheral_one,
  384. base::scoped_nsobject<NSDictionary>(AdvertisementData()), kTestRssi);
  385. base::scoped_nsobject<CBPeripheral> mock_peripheral_two(
  386. CreateMockPeripheral(kTestAddedDeviceNSUUID));
  387. ASSERT_TRUE(mock_peripheral_two);
  388. LowEnergyDeviceUpdated(
  389. mock_peripheral_two,
  390. base::scoped_nsobject<NSDictionary>(AdvertisementData()), kTestRssi);
  391. observer_.Reset();
  392. // BluetoothAdapterMac only notifies observers of changed devices detected by
  393. // BluetoothLowEnergyDeviceWatcherMac if the device has been already known to
  394. // the system(i.e. the changed device is in BluetoothAdatper::devices_). As
  395. // so, add mock devices prior to setting BluetoothLowenergyDeviceWatcherMac.
  396. SetFakeLowEnergyDeviceWatcher();
  397. EXPECT_EQ(1, observer_.device_changed_count());
  398. observer_.Reset();
  399. fake_low_energy_device_watcher_->SimulatePropertyListFileChanged(
  400. test_property_list_file_path_, kPropertyListFileContentWithAddedDevice);
  401. ui_task_runner_->RunUntilIdle();
  402. EXPECT_EQ(1, observer_.device_changed_count());
  403. EXPECT_TRUE(adapter_mac_->IsBluetoothLowEnergyDeviceSystemPaired(
  404. kTestAddedDeviceNSUUID));
  405. }
  406. TEST_F(BluetoothAdapterMacTest, NotifyObserverWhenDeviceIsUnpaired) {
  407. constexpr char kPropertyListFileContentWithRemovedDevice[] =
  408. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  409. "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
  410. "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
  411. "<plist version=\"1.0\">"
  412. "<dict>"
  413. " <key>CoreBluetoothCache</key>"
  414. " <dict> "
  415. " </dict>"
  416. "</dict>"
  417. "</plist>";
  418. if (!SetMockCentralManager(CBManagerStatePoweredOn))
  419. return;
  420. base::scoped_nsobject<CBPeripheral> mock_peripheral(
  421. CreateMockPeripheral(kTestNSUUID));
  422. if (!mock_peripheral)
  423. return;
  424. LowEnergyDeviceUpdated(
  425. mock_peripheral, base::scoped_nsobject<NSDictionary>(AdvertisementData()),
  426. kTestRssi);
  427. observer_.Reset();
  428. SetFakeLowEnergyDeviceWatcher();
  429. EXPECT_EQ(1, observer_.device_changed_count());
  430. observer_.Reset();
  431. fake_low_energy_device_watcher_->SimulatePropertyListFileChanged(
  432. test_property_list_file_path_, kPropertyListFileContentWithRemovedDevice);
  433. ui_task_runner_->RunUntilIdle();
  434. EXPECT_EQ(1, observer_.device_changed_count());
  435. EXPECT_FALSE(
  436. adapter_mac_->IsBluetoothLowEnergyDeviceSystemPaired(kTestNSUUID));
  437. }
  438. } // namespace device