Skip to content

Commit

Permalink
Updated project file and added GTXResult API
Browse files Browse the repository at this point in the history
  • Loading branch information
Sid Janga committed Feb 20, 2020
1 parent 641200f commit 02a890f
Show file tree
Hide file tree
Showing 14 changed files with 607 additions and 225 deletions.
2 changes: 2 additions & 0 deletions Classes/GTXArtifactProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ - (void)fetchLatestReportAsync:(GTXArtifactProcessorReportFetchBlock)fetchBlock

- (void)gtx_assertCallerIsCommandQueue {
void *context = dispatch_queue_get_specific(_commandQueue, _queueKey);
(void)context; // Marking context as used when below assert is removed due to compiler
// optimizations.
GTX_ASSERT(context == _queueContext, @"This method can only be executed from command queue.");
}

Expand Down
4 changes: 1 addition & 3 deletions Classes/GTXChecksCollection.m
Original file line number Diff line number Diff line change
Expand Up @@ -572,15 +572,13 @@ + (nullable NSString *)gtx_errorDescriptionForMinimumTappableArea:(CGRect)frame

/**
* Determines if @c frame satisfies minimum touch target guidelines, and if it doesn't, adds an
* error description to @c array.
* error description to @c array.
*
* @param frame The frame of an interactable element. This can be its frame, accessibilityFrame, or
* some other bounding box.
* @param propertyName The name of the element's property being checked. This is included in the
* description.
* @param array The array to which to add the error description, if it exists.
* @return A string describing the error, or @c nil if @c frame satisfies minimum touch target
* guidelines.
*/
+ (void)gtx_errorDescriptionForMinimumTappableArea:(CGRect)frame
propertyName:(NSString *)propertyName
Expand Down
64 changes: 64 additions & 0 deletions Classes/GTXResult.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// Copyright 2020 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

/**
GTXResult encapsulates results (and any other associated info) of a single pass of accessibility
checks.
*/
@interface GTXResult : NSObject

/**
An array of all the errors encountered during the accessibility check(s).
*/
@property(nonatomic, strong, readonly) NSArray<NSError *> *errorsFound;

/**
Total number of elements that passed through accessibilty check(s).
*/
@property(nonatomic, assign, readonly) NSInteger elementsScanned;

/**
Use -initWithErrorsFound:elementsScanned:
*/
- (instancetype)init NS_UNAVAILABLE;

/**
Initializes a new GTXResult object.
@param errorsFound Array of errors found.
@param elementsScanned Total number of elements scanned.
@return A newly created GTXResult object.
*/
- (instancetype)initWithErrorsFound:(NSArray<NSError *> *)errorsFound
elementsScanned:(NSInteger)elementsScanned;

/**
@return @YES if none of the checks failed, @NO otherwise.
*/
- (BOOL)allChecksPassed;

/**
@return The aggregated error of all the errors in this result, or @c nil if no errors were found.
*/
- (NSError *)aggregatedError;

@end

NS_ASSUME_NONNULL_END
83 changes: 83 additions & 0 deletions Classes/GTXResult.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// Copyright 2020 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "GTXResult.h"
#import "NSError+GTXAdditions.h"

NS_ASSUME_NONNULL_BEGIN

@interface GTXResult ()

@property(nonatomic, strong) NSArray<NSError *> *errorsFound;
@property(nonatomic, assign) NSInteger elementsScanned;

@end

@implementation GTXResult {
NSError *_aggregatedError;
}

- (instancetype)initWithErrorsFound:(NSArray<NSError *> *)errorsFound
elementsScanned:(NSInteger)elementsScanned {
self = [super init];
if (self) {
_errorsFound = errorsFound;
_elementsScanned = elementsScanned;
}
return self;
}

- (BOOL)allChecksPassed {
return self.errorsFound.count == 0;
}

- (NSError *)aggregatedError {
if (![self allChecksPassed]) {
// Combine the error descriptions from all the errors into the following format ('.' is an
// indent):
// . . Element: <element description>
// . . . . Error: <error description>
// . . . . Error: <error description>
// . . Element: <element description>
// . . . . Error: <error description>
// . . . . Error: <error description>

NSMutableString *errorString =
[[NSMutableString alloc] initWithString:@"One or more elements FAILED the accessibility "
@"checks:\n"];
for (NSError *error in self.errorsFound) {
id element = [[error userInfo] objectForKey:kGTXErrorFailingElementKey];
if (element) {
// Add element description with an indent.
[errorString appendFormat:@" %@\n", element];
for (NSError *underlyingError in
// Add element's error description with twice the indent.
[[error userInfo] objectForKey:kGTXErrorUnderlyingErrorsKey]) {
[errorString appendFormat:@" + %@\n", [underlyingError localizedDescription]];
}
}
}
[NSError gtx_logOrSetError:&_aggregatedError
description:errorString
code:GTXCheckErrorCodeGenericError
userInfo:@{kGTXErrorUnderlyingErrorsKey : self.errorsFound}];
}
return _aggregatedError;
}

@end

NS_ASSUME_NONNULL_END
78 changes: 29 additions & 49 deletions Classes/GTXTestEnvironment.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@ - (void)setAccessibilityPreferenceAsMobile:(CFStringRef)key
/**
* Path to accessibility utils framework on the simulator.
*/
static NSString *const kPathToAXUtils =
static NSString *const kGTXPathToAXUtils =
@"/System/Library/PrivateFrameworks/AccessibilityUtilities.framework/AccessibilityUtilities";

/**
* Class name of the private class: XCAXClient_iOS class.
* Path to accessibility dylib on the device.
*/
static NSString *const kXCAXClientClassName = @"XCAXClient_iOS";
static NSString *const kGTXPathToAXDyLib = @"/usr/lib/libAccessibility.dylib";

/**
* Name of the method that can enable accessibility.
*/
static char *const kGTXAXSetterMethodName = "_AXSSetAutomationEnabled";

#pragma mark - Implementations

Expand Down Expand Up @@ -123,7 +128,7 @@ + (BOOL)_setAccessibilityPreference:(CFStringRef)key
static AXBackBoardServer *server;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
char const *const localPath = [kPathToAXUtils fileSystemRepresentation];
char const *const localPath = [kGTXPathToAXUtils fileSystemRepresentation];
void *handle = dlopen(localPath, RTLD_LOCAL);
if (!handle) {
NSString *description =
Expand Down Expand Up @@ -163,57 +168,32 @@ + (BOOL)_setAccessibilityPreference:(CFStringRef)key
* Enables accessibility to allow using accessibility properties on devices.
*/
+ (BOOL)gtx_enableAccessibilityOnDeviceWithError:(GTXErrorRefType)errorOrNil {
Class XCAXClientClass = NSClassFromString(kXCAXClientClassName);
if (XCAXClientClass == nil) {
NSString *description = [NSString stringWithFormat:@"%@ class not found", kXCAXClientClassName];
[NSError gtx_logOrSetError:errorOrNil
description:description
code:GTXCheckErrorCodeInvalidTestEnvironment
userInfo:nil];
return NO;
}
id XCAXClient = [XCAXClientClass sharedClient];
if (XCAXClient == nil) {
GTX_LOG(@"Enabling accessibility to access UI accessibility properties.");
char const *const libAccessibilityPath = [kGTXPathToAXDyLib fileSystemRepresentation];
void *handle = dlopen(libAccessibilityPath, RTLD_LOCAL);

if (handle) {
void (*AXSetterMethod)(BOOL) = dlsym(handle, kGTXAXSetterMethodName);
if (AXSetterMethod) {
AXSetterMethod(YES);
return YES;
} else {
NSString *description = [NSString
stringWithFormat:@"Pointer to %s method must not be NULL", kGTXAXSetterMethodName];
[NSError gtx_logOrSetError:errorOrNil
description:description
code:GTXCheckErrorCodeInvalidTestEnvironment
userInfo:nil];
}
} else {
NSString *description =
[NSString stringWithFormat:@"%@ sharedClient doesn't exist", kXCAXClientClassName];
[NSString stringWithFormat:@"dlopen couldn't open libAccessibility.dylib at path %s",
libAccessibilityPath];
[NSError gtx_logOrSetError:errorOrNil
description:description
code:GTXCheckErrorCodeInvalidTestEnvironment
userInfo:nil];
return NO;
}
// The method may not be available on versions older than iOS 9.1
if ([XCAXClient respondsToSelector:@selector(loadAccessibility:)]) {
typedef void (*MethodType)(id, SEL, void*);
SEL selector = @selector(loadAccessibility:);
static void *unused = 0;
MethodType method = (MethodType)[XCAXClient methodForSelector:selector];
method(XCAXClient, selector, &unused);
} else {
[NSError gtx_logOrSetError:errorOrNil
description:@"Could not enable accessibility! iOS version must be >= 9.1"
code:GTXCheckErrorCodeInvalidTestEnvironment
userInfo:nil];
return NO;
}
return YES;
}

#pragma mark - unused methods

/**
* Unused method only used for selector name.
*/
- (id)sharedClient {
NSAssert(NO, @"This method must not be invoked directly, its only used for exposing selector");
return nil;
}

/**
* Unused method only used for selector name.
*/
- (BOOL)loadAccessibility:(void **)unused {
NSAssert(NO, @"This method must not be invoked directly, its only used for exposing selector");
return NO;
}

Expand Down
15 changes: 13 additions & 2 deletions Classes/GTXToolKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#import "GTXBlacklisting.h"
#import "GTXCheckBlock.h"
#import "GTXChecking.h"
#import "GTXResult.h"

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -83,15 +84,25 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)checkElement:(id)element error:(GTXErrorRefType)errorOrNil;

/**
@deprecated Use -resultFromCheckingAllElementsFromRootElements: instead.
Applies the registered checks on all elements in the accessibility tree under the given root
elements while respecting blacklisted elements.
@param rootElements An array of root elements whose accessibility trees are to be checked.
@param errorOrNil Error object to be filled with error info on check failures.
@return @c YES if all checks passed on all elements @c NO otherwise.
*/
- (BOOL)checkAllElementsFromRootElements:(NSArray *)rootElements
error:(GTXErrorRefType)errorOrNil;
- (BOOL)checkAllElementsFromRootElements:(NSArray *)rootElements error:(GTXErrorRefType)errorOrNil;

/**
Applies the registered checks on all elements in the accessibility tree under the given root
elements while respecting blacklisted elements.
@param rootElements An array of root elements whose accessibility trees are to be checked.
@return A @c GTXResult object encpsulating the results.
*/
- (GTXResult *)resultFromCheckingAllElementsFromRootElements:(NSArray *)rootElements;

@end

Expand Down
Loading

0 comments on commit 02a890f

Please sign in to comment.