223 lines
9.8 KiB
Swift
223 lines
9.8 KiB
Swift
/*
|
|
* Copyright (c) 2020, Nordic Semiconductor
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
import XCTest
|
|
@testable import nRF_Blinky
|
|
@testable import CoreBluetoothMock
|
|
|
|
class RetrievingDevicesTest: XCTestCase {
|
|
|
|
override func setUpWithError() throws {
|
|
// This method is called AFTER ScannerTableViewController.viewDidLoad()
|
|
// where the BlinkyManager is instantiated. A separate mock manager
|
|
// is not created in this test.
|
|
// Initially mock Bluetooth adapter is powered Off.
|
|
CBMCentralManagerMock.simulatePeripherals([blinky, hrm, thingy])
|
|
CBMCentralManagerMock.simulateInitialState(.poweredOn)
|
|
}
|
|
|
|
override func tearDownWithError() throws {
|
|
// We can't call CBMCentralManagerMock.tearDownSimulation() here.
|
|
// That would invalidate the BlinkyManager in ScannerTableViewController.
|
|
// The central manager must be reused, so let's just power mock off,
|
|
// which will allow us to set different set of peripherals in another test.
|
|
CBMCentralManagerMock.simulatePowerOff()
|
|
}
|
|
|
|
func testRetrieval() throws {
|
|
// Devices might have been scanned and cached by some other test.
|
|
// Make sure they're treated as new devices by changing their addresses.
|
|
blinky.simulateMacChange()
|
|
hrm.simulateMacChange()
|
|
|
|
let managerPoweredOn = XCTestExpectation(description: "Powered On")
|
|
|
|
// Define the CBCentralManagerDelegate, which will wait until the manager is ready.
|
|
let delegate = CBMCentralManagerDelegateProxy()
|
|
delegate.didUpdateState = { _ in managerPoweredOn.fulfill() }
|
|
|
|
// Create an instance of mock CBMCentralManager.
|
|
let manager = CBMCentralManagerMock(delegate: delegate, queue: nil)
|
|
|
|
// Wait until the manager is initialized.
|
|
wait(for: [managerPoweredOn], timeout: 1.0)
|
|
|
|
// Initially, none of the devices should be retrievable, as they have not been scanned.
|
|
let list1 = manager.retrievePeripherals(withIdentifiers: [blinky.identifier, hrm.identifier])
|
|
XCTAssertTrue(list1.isEmpty)
|
|
|
|
// Simulate a situation when a different app on the iPhone scanned the Blinky device
|
|
// causing it to be cached.
|
|
//
|
|
// Note: This should also work when the device is out of range, as undefined time can pass
|
|
// between retrievals, so it could have been close for a moment, and taken away again.
|
|
blinky.simulateCaching()
|
|
|
|
// Now the Blinky should be available for retrieval.
|
|
let list2 = manager.retrievePeripherals(withIdentifiers: [blinky.identifier, hrm.identifier])
|
|
XCTAssertEqual(list2.count, 1)
|
|
XCTAssert(list2.contains(where: { $0.identifier == blinky.identifier }))
|
|
}
|
|
|
|
func testRetrievalAfterScanning() throws {
|
|
// Set up the devices in range.
|
|
thingy.simulateMacChange()
|
|
thingy.simulateProximityChange(.immediate)
|
|
|
|
let managerPoweredOn = XCTestExpectation(description: "Powered On")
|
|
let thingyFound = XCTestExpectation(description: "Found")
|
|
let thingyRetrieved = XCTestExpectation(description: "Retrieved")
|
|
|
|
// Define the CBCentralManagerDelegate, which will wait until the manager is ready
|
|
// and will check the successful retrieval.
|
|
let delegate = CBMCentralManagerDelegateProxy()
|
|
delegate.didUpdateState = { _ in managerPoweredOn.fulfill() }
|
|
delegate.didDiscoverPeripheral = { manager, peripheral, _, _ in
|
|
guard peripheral.identifier == thingy.identifier else { return }
|
|
thingyFound.fulfill()
|
|
|
|
// Now it should be available for retrieval.
|
|
let list = manager.retrievePeripherals(withIdentifiers: [thingy.identifier])
|
|
XCTAssertFalse(list.isEmpty)
|
|
|
|
if !list.isEmpty {
|
|
thingyRetrieved.fulfill()
|
|
}
|
|
}
|
|
|
|
// Create an instance of a mock CBMCentralManager.
|
|
let manager = CBMCentralManagerMock(delegate: delegate, queue: nil)
|
|
|
|
// Wait until the manager is initialized.
|
|
wait(for: [managerPoweredOn], timeout: 1.0)
|
|
|
|
// Initially, none of the devices should be retrievable, as they have not been scanned.
|
|
let list = manager.retrievePeripherals(withIdentifiers: [thingy.identifier])
|
|
XCTAssertTrue(list.isEmpty)
|
|
|
|
// Start scanning for any device.
|
|
manager.scanForPeripherals(withServices: nil)
|
|
|
|
// Wait until the device is found and could be retrieved.
|
|
wait(for: [thingyFound, thingyRetrieved], timeout: 1.0)
|
|
}
|
|
|
|
func testRetrievalConnected() throws {
|
|
let hrmServiceUUID = CBMUUID(string: "180D")
|
|
|
|
// Set up the devices in range.
|
|
hrm.simulateMacChange()
|
|
hrm.simulateProximityChange(.near)
|
|
blinky.simulateProximityChange(.immediate)
|
|
thingy.simulateProximityChange(.far)
|
|
|
|
let managerPoweredOn = XCTestExpectation(description: "Powered On")
|
|
let hrmFound = XCTestExpectation(description: "Found")
|
|
let otherFound = XCTestExpectation(description: "Other found")
|
|
otherFound.isInverted = true
|
|
let hrmRetrieved = XCTestExpectation(description: "Retrieved after service discovery")
|
|
let hrmNotRetrieved = XCTestExpectation(description: "Not retrieved as not connected")
|
|
let hrmStillNotRetrieved = XCTestExpectation(description: "Not retrieved as services not discovered")
|
|
|
|
// Create an instance of a mock CBMCentralManager.
|
|
let manager = CBMCentralManagerMock()
|
|
|
|
// Define the CBMPeripheralDelegate, which will wait until the serivces are
|
|
// discovered and will try to retrieve the device.
|
|
let peripheralDelegate = CBMPeripheralDelegateProxy()
|
|
peripheralDelegate.didDiscoverServices = { peripheral, error in
|
|
XCTAssertNil(error)
|
|
|
|
// HRM device should now be connected and retrievable.
|
|
let list = manager.retrieveConnectedPeripherals(withServices: [hrmServiceUUID])
|
|
XCTAssertFalse(list.isEmpty)
|
|
|
|
if !list.isEmpty {
|
|
hrmRetrieved.fulfill()
|
|
}
|
|
}
|
|
|
|
// Define the CBCentralManagerDelegate, which will wait until the manager is ready
|
|
// and will check the successful retrieval.
|
|
let delegate = CBMCentralManagerDelegateProxy()
|
|
delegate.didUpdateState = { _ in managerPoweredOn.fulfill() }
|
|
delegate.didDiscoverPeripheral = { manager, peripheral, _, _ in
|
|
guard peripheral.identifier == hrm.identifier else {
|
|
otherFound.fulfill()
|
|
return
|
|
}
|
|
hrmFound.fulfill()
|
|
|
|
// HRM device should still not be connected and retrievable.
|
|
let list = manager.retrieveConnectedPeripherals(withServices: [hrmServiceUUID])
|
|
XCTAssertTrue(list.isEmpty)
|
|
|
|
if list.isEmpty {
|
|
hrmNotRetrieved.fulfill()
|
|
}
|
|
|
|
// Connect to the device when found.
|
|
peripheral.delegate = peripheralDelegate
|
|
manager.connect(peripheral)
|
|
}
|
|
delegate.didConnect = { manager, peripheral in
|
|
// HRM device should still not be connected and retrievable.
|
|
let list = manager.retrieveConnectedPeripherals(withServices: [hrmServiceUUID])
|
|
XCTAssertTrue(list.isEmpty)
|
|
|
|
if list.isEmpty {
|
|
hrmStillNotRetrieved.fulfill()
|
|
}
|
|
|
|
// Discover services.
|
|
peripheral.discoverServices([hrmServiceUUID])
|
|
}
|
|
manager.delegate = delegate
|
|
|
|
// Wait until the manager is initialized.
|
|
wait(for: [managerPoweredOn], timeout: 1.0)
|
|
|
|
// Initially, none of the devices should be retrievable, as they have not been scanned.
|
|
let list = manager.retrieveConnectedPeripherals(withServices: [hrmServiceUUID])
|
|
XCTAssertTrue(list.isEmpty)
|
|
|
|
// Scan only for HRM device. Other devices may also be in range.
|
|
manager.scanForPeripherals(withServices: [hrmServiceUUID])
|
|
|
|
wait(for: [
|
|
hrmFound, otherFound,
|
|
hrmNotRetrieved, hrmStillNotRetrieved, hrmRetrieved
|
|
],
|
|
timeout: 4.0)
|
|
}
|
|
|
|
}
|