TestHIDDisplayFramework.m [plain text]
//
// TestHIDDisplayFramework.m
// IOHIDFamilyUnitTests
//
// Created by AB on 1/11/19.
//
#import <XCTest/XCTest.h>
#import <HIDDisplay/HIDDisplay.h>
#import <IOKit/hid/IOHIDKeys.h>
#import <IOKit/hid/IOHIDUserDevice.h>
#import <IOKit/hid/AppleHIDUsageTables.h>
#import <XCTest/XCTMemoryChecker.h>
#import <IOKit/usb/USBSpec.h>
#import "IOHIDXCTestExpectation.h"
#import "IOHIDUnitTestUtility.h"
#import "IOHIDUnitTestDescriptors.h"
#import <TargetConditionals.h>
static NSString * deviceDescription =
@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
" <plist version=\"1.0\"> "
" <dict> "
" <key>VendorID</key> "
" <integer>855</integer> "
" <key>ProductID</key> "
" <integer>855</integer> "
" <key>ReportInterval</key> "
" <integer>10000</integer> "
" <key>RequestTimeout</key> "
" <integer>5000000</integer> "
" <key>UnitTestService</key> "
" <true/> "
" </dict> "
" </plist> ";
#define kTestPresetCount 50
#define kTestDefaultFactoryPresetIndex 3
#define kTestDefaultActivePresetIndex 5
static uint8_t descriptor [] = {
AppleVendorDisplayPreset
};
static AppleVendorDisplayFeatureReport03 presetData[kTestPresetCount];
static AppleVendorDisplayFeatureReport02 featureReport2;
static AppleVendorDisplayFeatureReport01 featureReport1;
static NSMutableArray<NSString*> *presetUUIDs;
static void __initPresets()
{
presetUUIDs = [[NSMutableArray alloc] init];
for (NSInteger i=0; i < kTestPresetCount; i++) {
memset(&presetData[i], 0, sizeof(AppleVendorDisplayFeatureReport03));
presetData[i].reportId = 0x17;
presetData[i].AppleVendor_DisplayPresetWritable = (i presetData[i].AppleVendor_DisplayPresetValid = (i
NSString *testName = [NSString stringWithFormat:@"TestšPresetName_ NSString *testDescription = [NSString stringWithFormat:@"TestšPresetDescription_ unichar testNameUnichar[256];
unichar testDescriptionUnichar[512];
[testName getBytes:testNameUnichar maxLength:256 usedLength:NULL encoding:NSUTF16LittleEndianStringEncoding options:0 range:NSMakeRange(0, 256) remainingRange:NULL];
[testDescription getBytes:testDescriptionUnichar maxLength:512 usedLength:NULL encoding:NSUTF16LittleEndianStringEncoding options:0 range:NSMakeRange(0, 512) remainingRange:NULL];
memcpy(presetData[i].AppleVendor_DisplayPresetUnicodeStringName, testNameUnichar, 256);
memcpy(presetData[i].AppleVendor_DisplayPresetUnicodeStringDescription, testDescriptionUnichar, 512);
presetData[i].AppleVendor_DisplayPresetDataBlockOneLength = 64;
snprintf((char*)presetData[i].AppleVendor_DisplayPresetDataBlockOne, 64, "TestPresetDataBlockOne_ presetData[i].AppleVendor_DisplayPresetDataBlockTwoLength = 192;
snprintf((char*)presetData[i].AppleVendor_DisplayPresetDataBlockTwo, 192, "TestPresetDataBlockTwo_ NSString *uuid = [[[NSUUID alloc] init] UUIDString];
snprintf((char*)presetData[i].AppleVendor_DisplayPresetUUID, 128, " [presetUUIDs addObject:uuid];
}
memset(&featureReport1, 0, sizeof(AppleVendorDisplayFeatureReport01));
memset(&featureReport2, 0, sizeof(AppleVendorDisplayFeatureReport02));
featureReport2.reportId = 0x16;
featureReport1.reportId = 0x15;
featureReport1.AppleVendor_DisplayFactoryDefaultPresetIndex = kTestDefaultFactoryPresetIndex;
featureReport1.AppleVendor_DisplayActivePresetIndex = kTestDefaultActivePresetIndex;
}
@interface TestHIDDisplayFramework : XCTestCase
{
IOHIDUserDeviceRef _userDevice;
HIDDisplayDeviceRef _hidDisplayDevice;
dispatch_queue_t _queue;
NSString *_containerID;
XCTMemoryChecker *_memoryChecker;
NSUInteger _presetCount;
}
@property XCTestExpectation *testSetReportExpectation;
@property XCTestExpectation *testGetReportExpectation;
@property NSInteger getReportCount;
@property NSInteger setReportCount;
@end
static IOReturn __setReportCallback(void * _Nullable refcon, IOHIDReportType __unused type, uint32_t __unused reportID, uint8_t * report __unused, CFIndex reportLength __unused) {
TestHIDDisplayFramework *selfRef = (__bridge TestHIDDisplayFramework*)refcon;
selfRef.setReportCount++;
if (selfRef.setReportCount == 50) {
[selfRef.testSetReportExpectation fulfill];
}
switch (reportID) {
case 0x15:
bcopy(report, &featureReport1, sizeof(AppleVendorDisplayFeatureReport01));
break;
case 0x16:
bcopy(report, &featureReport2, sizeof(AppleVendorDisplayFeatureReport02));
break;
case 0x17: {
NSInteger currentIndex = featureReport2.AppleVendor_DisplayCurrentPresetIndex;
if (currentIndex < kTestPresetCount) {
bcopy(report, &presetData[currentIndex], sizeof(AppleVendorDisplayFeatureReport03));
}
break;
}
default:
break;
}
return kIOReturnSuccess;
}
static IOReturn __getReportCallback(void * _Nullable refcon __unused, IOHIDReportType type __unused, uint32_t reportID , uint8_t * report , CFIndex reportLength __unused) {
TestHIDDisplayFramework *selfRef = (__bridge TestHIDDisplayFramework*)refcon;
selfRef.getReportCount++;
if (selfRef.getReportCount == 52) {
[selfRef.testGetReportExpectation fulfill];
}
switch (reportID) {
case 0x15:
bcopy(&featureReport1, report, reportLength);
break;
case 0x16:
bcopy(&featureReport2, report, reportLength);
break;
case 0x17: {
NSInteger currentIndex = featureReport2.AppleVendor_DisplayCurrentPresetIndex;
if (currentIndex < kTestPresetCount) {
bcopy(&presetData[currentIndex], report, reportLength);
}
break;
}
default:
break;
}
return kIOReturnSuccess;
}
@implementation TestHIDDisplayFramework
- (void)setUp {
[super setUp];
_containerID = [[[NSUUID alloc] init] UUIDString];
_memoryChecker = [[XCTMemoryChecker alloc]initWithDelegate:self];
NSMutableDictionary* deviceConfig = [NSPropertyListSerialization propertyListWithData:[deviceDescription dataUsingEncoding:NSUTF8StringEncoding] options:NSPropertyListMutableContainers format:NULL error:NULL];
NSData *descriptorData = [[NSData alloc] initWithBytes:descriptor length:sizeof(descriptor)];
deviceConfig [@kIOHIDReportDescriptorKey] = descriptorData;
#if !TARGET_OS_IPHONE || TARGET_OS_IOSMAC
deviceConfig [@kUSBDeviceContainerID] = _containerID;
#else
deviceConfig [@kUSBContainerID] = _containerID;
#endif
_userDevice = IOHIDUserDeviceCreate(kCFAllocatorDefault, (CFDictionaryRef)deviceConfig);
HIDXCTAssertWithParameters (RETURN_FROM_TEST | COLLECT_LOGARCHIVE, _userDevice != NULL);
IOHIDUserDeviceRegisterSetReportCallback(_userDevice, __setReportCallback, (__bridge void*)self);
IOHIDUserDeviceRegisterGetReportCallback(_userDevice, __getReportCallback, (__bridge void*)self);
_queue = dispatch_queue_create("com.apple.user-device-test", NULL);
HIDXCTAssertWithParameters (RETURN_FROM_TEST | COLLECT_LOGARCHIVE, _queue != NULL);
IOHIDUserDeviceScheduleWithDispatchQueue (_userDevice, _queue);
__initPresets();
// Expectation count for set report
// 50 ( 50 for preset select)
// Expection count for get report
// 52 (50 for copy preset + 2 for factory and active preset)
_testSetReportExpectation = [[XCTestExpectation alloc] initWithDescription:@"Expectation: set reports"];
_testGetReportExpectation = [[XCTestExpectation alloc] initWithDescription:@"Expectation: get reports"];
}
- (void)tearDown {
IOHIDUserDeviceUnscheduleFromDispatchQueue (_userDevice, _queue);
CFRelease(_userDevice);
}
// test initial info on presets
-(void) TestPresetDefaultInfo
{
_presetCount = (NSUInteger)HIDDisplayGetPresetCount(_hidDisplayDevice);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , _presetCount == kTestPresetCount);
NSInteger factoryDefaultIndex = HIDDisplayGetFactoryDefaultPresetIndex(_hidDisplayDevice, NULL);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , factoryDefaultIndex == kTestDefaultFactoryPresetIndex);
NSInteger activePresetIndex = HIDDisplayGetActivePresetIndex(_hidDisplayDevice, NULL);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , activePresetIndex == kTestDefaultActivePresetIndex || activePresetIndex == kTestDefaultFactoryPresetIndex);
for (NSUInteger i=0; i < _presetCount; i++) {
NSDictionary *info = (__bridge_transfer NSDictionary*)HIDDisplayCopyPreset(_hidDisplayDevice,i, nil);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , info != nil);
NSString* name = info[(__bridge NSString*)kHIDDisplayPresetFieldNameKey];
NSString* desc = info[(__bridge NSString*)kHIDDisplayPresetFieldDescriptionKey];
NSString* dataBlockOne = [NSString stringWithUTF8String:[info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockOneKey] bytes]];
NSNumber *dataBlockOneLength = info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockOneLengthKey];
NSString* dataBlockTwo = [NSString stringWithUTF8String:[info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockTwoKey] bytes]];
NSNumber *dataBlockTwoLength = info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockTwoLengthKey];
NSString* uuid = info[(__bridge NSString*)kHIDDisplayPresetUniqueIDKey];
HIDXCTAssertWithParameters (RETURN_FROM_TEST , dataBlockOneLength.integerValue == 64);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , dataBlockTwoLength.integerValue == 192);
NSString *expectedName = [NSString stringWithFormat:@"TestšPresetName_ NSString *expectedDesc = [NSString stringWithFormat:@"TestšPresetDescription_ NSString *expectedDataBlockOne = [NSString stringWithFormat:@"TestPresetDataBlockOne_ NSString *expectedDataBlockTwo = [NSString stringWithFormat:@"TestPresetDataBlockTwo_
HIDXCTAssertWithParameters (RETURN_FROM_TEST , name && [name hasPrefix:expectedName]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , desc && [desc hasPrefix:expectedDesc]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , dataBlockOne && [expectedDataBlockOne isEqualToString:dataBlockOne]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , dataBlockTwo && [expectedDataBlockTwo isEqualToString:dataBlockTwo]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , uuid && [uuid isEqualToString:presetUUIDs[i]]);
}
XCTWaiterResult result = [XCTWaiter waitForExpectations:@[_testSetReportExpectation,_testGetReportExpectation] timeout:10];
HIDXCTAssertWithParameters (RETURN_FROM_TEST,
result == XCTWaiterResultCompleted,
"result: (long)result, _getReportCount, _setReportCount,
_testSetReportExpectation,_testGetReportExpectation);
}
// modify preset info
-(void) TestSetPresetInfo
{
for (NSInteger i=0; i < _presetCount; i++) {
bool isValid = HIDDisplayIsPresetValid(_hidDisplayDevice, i);
//valid preset (check __initPreset for description)
if (i HIDXCTAssertWithParameters (RETURN_FROM_TEST , isValid == true);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , HIDDisplaySetActivePresetIndex(_hidDisplayDevice, i, NULL) == true);
} else {
HIDXCTAssertWithParameters (RETURN_FROM_TEST , isValid == false);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , HIDDisplaySetActivePresetIndex(_hidDisplayDevice, i, NULL) == false);
}
//writable preset, valid preset
if (i
//invalidate preset
NSDictionary *info = @{(__bridge NSString*)kHIDDisplayPresetFieldValidKey : @(0)};
bool ret = HIDDisplaySetPreset(_hidDisplayDevice, i, (__bridge CFDictionaryRef)info, nil);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , ret == true);
isValid = HIDDisplayIsPresetValid(_hidDisplayDevice, i);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , isValid == false);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , HIDDisplaySetActivePresetIndex(_hidDisplayDevice, i, NULL) == false);
NSString *expectedName = [NSString stringWithFormat:@"ModifiedTestPresetšName_ NSString *expectedDesc = [NSString stringWithFormat:@"ModifiedTestPresetšDescription_
NSString *expectedDataBlockOne = [NSString stringWithFormat:@"ModifiedTestPresetDataBlockOne_ NSString *expectedDataBlockTwo = [NSString stringWithFormat:@"ModifiedTestPresetDataBlockTwo_ NSString *expectedUUID = [[[NSUUID alloc] init] UUIDString];
info = @{
(__bridge NSString*)kHIDDisplayPresetFieldNameKey : expectedName,
(__bridge NSString*)kHIDDisplayPresetFieldDescriptionKey : expectedDesc,
(__bridge NSString*)kHIDDisplayPresetFieldDataBlockOneKey : [expectedDataBlockOne dataUsingEncoding:NSUTF8StringEncoding],
(__bridge NSString*)kHIDDisplayPresetFieldDataBlockTwoKey : [expectedDataBlockTwo dataUsingEncoding:NSUTF8StringEncoding],
(__bridge NSString*)kHIDDisplayPresetFieldDataBlockOneLengthKey : @(12+i),
(__bridge NSString*)kHIDDisplayPresetFieldDataBlockTwoLengthKey : @(16+i),
(__bridge NSString*)kHIDDisplayPresetUniqueIDKey : expectedUUID,
};
ret = HIDDisplaySetPreset(_hidDisplayDevice, i, (__bridge CFDictionaryRef)info, nil);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , ret == true);
info = (__bridge_transfer NSDictionary*)HIDDisplayCopyPreset(_hidDisplayDevice,i, nil);
NSString* name = info[(__bridge NSString*)kHIDDisplayPresetFieldNameKey];
NSString* desc = info[(__bridge NSString*)kHIDDisplayPresetFieldDescriptionKey];
NSString* dataBlockOne = [NSString stringWithUTF8String:[info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockOneKey] bytes]];
NSString* dataBlockTwo = [NSString stringWithUTF8String:[info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockTwoKey] bytes]];
NSNumber *dataBlockOneLength = info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockOneLengthKey];
NSNumber *dataBlockTwoLength = info[(__bridge NSString*)kHIDDisplayPresetFieldDataBlockTwoLengthKey];
NSString *uniqueID = info[(__bridge NSString*)kHIDDisplayPresetUniqueIDKey];
HIDXCTAssertWithParameters (RETURN_FROM_TEST , name && [name containsString:expectedName]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , desc && [desc containsString:expectedDesc]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , dataBlockOne && [expectedDataBlockOne isEqualToString:dataBlockOne]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , dataBlockTwo && [expectedDataBlockTwo isEqualToString:dataBlockTwo]);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , (unsigned long)dataBlockOneLength.integerValue == 12+i);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , (unsigned long)dataBlockTwoLength.integerValue == 16+i);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , uniqueID && [expectedUUID isEqualToString:uniqueID]);
}
//non writable preset
if (i NSDictionary *info = @{(__bridge NSString*)kHIDDisplayPresetFieldValidKey : @(0)};
bool ret = HIDDisplaySetPreset(_hidDisplayDevice, i, (__bridge CFDictionaryRef)info, nil);
HIDXCTAssertWithParameters (RETURN_FROM_TEST , ret == false);
}
}
}
- (void)testHIDDisplayFramework {
[_memoryChecker assertObjectsOfTypes:@[@"HIDDisplayDevice", @"HIDDisplayDevicePreset",@"IOHIDDevice",@"HIDElement",@"IOHIDTransaction", @"IOHIDManager"] invalidAfterScope:^{
@autoreleasepool {
_hidDisplayDevice = HIDDisplayCreateDeviceWithContainerID((__bridge CFStringRef)_containerID);
HIDXCTAssertWithParameters (RETURN_FROM_TEST | COLLECT_LOGARCHIVE, _hidDisplayDevice != NULL);
[self TestPresetDefaultInfo];
[self TestSetPresetInfo];
CFRelease(_hidDisplayDevice);
}
}];
}
@end