TestElementBounds.swift [plain text]
//
// TestElementBounds.swift
// IOHIDFamilyUnitTests
//
// Created by dekom on 8/15/18.
//
import Foundation
import XCTest
import HID
// We need the @objc(TestElementBounds) so this class can be picked up by
// hidxctest, otherwise the call to testSuiteForTestCaseWithName will fail.
// See rdar://problem/43437350
@objc(TestElementBounds) class TestElementBounds : XCTestCase {
var userDevice : HIDUserDevice!
var device : HIDDevice!
var manager : HIDManager!
var numlockOOB : Int = 0
var capslockOOB : Int = 1
static let descriptor : [UInt8] = [
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x19, 0xE0, // Usage Minimum........... (224)
0x29, 0xE7, // Usage Maximum........... (231)
0x15, 0x00, // Logical Minimum......... (0)
0x25, 0x01, // Logical Maximum......... (1)
0x75, 0x01, // Report Size............. (1)
0x95, 0x08, // Report Count............ (8)
0x81, 0x02, // Input...................(Data, Variable, Absolute)
0x05, 0x08, // Usage Page (LED)
0x09, 0x01, // Usage (Num Lock)
0x75, 0x08, // Report Size............. (8)
0x95, 0x01, // Report Count............ (1)
0x15, 0x00, // Logical Minimum......... (0)
0x25, 0x05, // Logical Maximum......... (5)
0x91, 0x02, // Output..................(Data, Variable, Absolute)
0x09, 0x02, // Usage (Caps Lock)
0x15, 0x05, // Logical Minimum......... (5)
0x25, 0x0A, // Logical Maximum......... (10)
0x91, 0x02, // Output..................(Data, Variable, Absolute)
0xC0, // End Collection
]
override func setUp() {
super.setUp()
let desc = NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: TestElementBounds.descriptor),
length: TestElementBounds.descriptor.count,
freeWhenDone: false)
let uuid = UUID()
let properties : [String : Any] = [kIOHIDReportDescriptorKey: desc,
kIOHIDPhysicalDeviceUniqueIDKey: uuid.uuidString]
guard let userDevice = HIDUserDevice(properties: properties) else {
XCTAssert(false, "Failed to create HIDUserDevice")
return
}
userDevice.setSetReportHandler { (reportType, reportID, report, reportLength) -> IOReturn in
XCTAssert(reportType == HIDReportType.output)
XCTAssert(reportLength == 2)
// numlock out of bounds
// logical min/max for numlock report is 0-5, so anything outside
// of that is out of bounds
if report[0] > 5 {
self.numlockOOB = Int(report[0])
print("Detected numlock OOB value \(self.numlockOOB)")
}
// capslock out of bounds
// logical min/max for capslock report is 5-10, so anything outside
// of that is out of bounds
if report[1] < 5 || report[1] > 10 {
self.capslockOOB = Int(report[1])
print("Detected capslock OOB value \(self.capslockOOB)")
}
return kIOReturnSuccess
}
let q = DispatchQueue(label: "")
userDevice.setDispatchQueue(q)
userDevice.activate()
let deviceExp = XCTestExpectation(description: "HIDUserDevice enuemration")
let manager = HIDManager()
manager.setDeviceMatching([kIOHIDPhysicalDeviceUniqueIDKey : uuid.uuidString])
manager.setDeviceNotificationHandler { (device, added) in
if added {
print("Device added \(device)")
self.device = device
deviceExp.fulfill()
}
}
manager.setDispatchQueue(q)
manager.open()
manager.activate()
let result = XCTWaiter.wait(for: [deviceExp], timeout: 5)
XCTAssert(result == XCTWaiter.Result.completed)
self.userDevice = userDevice
self.manager = manager
}
override func tearDown() {
manager.close()
manager.cancel()
userDevice.cancel()
super.tearDown()
}
func testOutOfBounds() {
for element in device.elements(matching: [:]) {
if element.usage == kHIDUsage_LED_NumLock ||
element.usage == kHIDUsage_LED_CapsLock {
element.integerValue = 5
do {
try device.commit([element], direction: HIDDeviceCommitDirection.out)
} catch let error as NSError {
print("device.setElementValue failed: \(error)")
}
}
}
// Since numlock logical min/max is 0-5, we would expect an out of
// bounds value of 6 to be set
XCTAssert(numlockOOB == 6)
// Since capslock logical min/max is 5-10, we would expect an out of
// bounds value of 0 to be set
XCTAssert(capslockOOB == 0)
}
}