Skip to content

Commit

Permalink
Added classes for artifact collection and processing. Updated contras…
Browse files Browse the repository at this point in the history
…t and toouch target checks for accuracy. Changed all private method names to include appropriate prefix.

Added the following classes GTXArtifactCollector, GTXArtifactProcessor, GTXError, GTXReport, GTXSnapshotBuffer, GTXSnapshotContainer. Updated all prefixes of private methods from  "_" to "gtx_" or "gtxtest_" for tests. Updated contrast check calculation accuracy. Updated touch target check to include frame as well as accessibility frame. And minot refactoring.
  • Loading branch information
j-sid committed Jan 24, 2020
1 parent 34f9b74 commit 42c7a1d
Show file tree
Hide file tree
Showing 40 changed files with 2,483 additions and 502 deletions.
4 changes: 2 additions & 2 deletions Classes/GTXAnalytics.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ + (void)load {
[GTXAnalyticsUtils sendEventHitWithTrackingID:kGTXAnalyticsTrackingID
clientID:[GTXAnalyticsUtils clientID]
category:@"GTXiLibLib"
action:[self _NSStringFromAnalyticsEvent:event]
action:[self gtx_NSStringFromAnalyticsEvent:event]
value:@"1"];
};
}
Expand Down Expand Up @@ -79,7 +79,7 @@ + (void)invokeAnalyticsEvent:(GTXAnalyticsEvent)event {
@param event The event whose string value is needed.
@return String value for the given GTXAnalyticsEvent.
*/
+ (NSString *)_NSStringFromAnalyticsEvent:(GTXAnalyticsEvent)event {
+ (NSString *)gtx_NSStringFromAnalyticsEvent:(GTXAnalyticsEvent)event {
switch (event) {
case GTXAnalyticsEventChecksPerformed: return @"checkRan";
case GTXAnalyticsEventChecksFailed: return @"checkFailed";
Expand Down
43 changes: 43 additions & 0 deletions Classes/GTXArtifactCollector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright 2019 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 <Foundation/Foundation.h>

#import "GTXChecking.h"
#import "GTXSnapshotContainer.h"

NS_ASSUME_NONNULL_BEGIN

/**
* A class to streamline snapshot collection for a given set of checks.
*/
@interface GTXArtifactCollector : NSObject

/**
* Initializes an artifact collector to work with the given set of @c checks.
*/
- (instancetype)initWithChecks:(NSArray<id<GTXChecking>> *)checks;

/**
* @return a snapshot container with all the artifact snapshots needed by the checks. This method
* must only be invoked on the main thread to allow for UI related artifacts to be
* collected.
*/
- (GTXSnapshotContainer *)snapshot;

@end

NS_ASSUME_NONNULL_END
52 changes: 52 additions & 0 deletions Classes/GTXArtifactCollector.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// Copyright 2019 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 <Foundation/Foundation.h>

#import "GTXArtifactCollector.h"
#import "GTXAssertions.h"

@implementation GTXArtifactCollector {
NSArray<Class<GTXArtifactImplementing>> *_artifactClasses;
}

- (instancetype)initWithChecks:(NSArray<id<GTXChecking>> *)checks {
self = [super init];
if (self) {
// Get the set of all (unique) Artifact classes that the checks need.
NSMutableSet *classes = [[NSMutableSet alloc] init];
for (id<GTXChecking> check in checks) {
if ([check respondsToSelector:@selector(requiredArtifactClasses)]) {
[classes addObjectsFromArray:[check requiredArtifactClasses]];
}
}
_artifactClasses = [classes allObjects];
}
return self;
}

- (GTXSnapshotContainer *)snapshot {
GTX_ASSERT([NSThread isMainThread], @"Snapshots cannot be taken on non-main threads");
NSMutableArray<id<GTXArtifactImplementing>> *snapshots = [[NSMutableArray alloc] init];
for (Class<GTXArtifactImplementing> cls in _artifactClasses) {
id<GTXArtifactImplementing> snapshot = [cls createArtifactSnapshot];
GTX_ASSERT(snapshot, @"Could not fetch a snapshot");
[snapshots addObject:snapshot];
}
return snapshots.count > 0 ? [[GTXSnapshotContainer alloc] initWithSnapshots:snapshots] : nil;
}

@end
34 changes: 34 additions & 0 deletions Classes/GTXArtifactImplementing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Copyright 2019 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

/**
* A protocol that all artifacts must implement to ensure that snapshots can be taken.
*/
@protocol GTXArtifactImplementing <NSObject>

/**
* @return a new snapshot object with data captured at the time of invocation. This method is only
* invoked on the main thread.
*/
+ (instancetype)createArtifactSnapshot;

@end

NS_ASSUME_NONNULL_END
86 changes: 86 additions & 0 deletions Classes/GTXArtifactProcessor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// Copyright 2019 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 <Foundation/Foundation.h>

#import "GTXChecking.h"
#import "GTXSnapshotContainer.h"

NS_ASSUME_NONNULL_BEGIN

/**
* A delegate protocol for listening to events occurring in the @c GTXArtifactProcessor.
*/
@protocol GTXArtifactProcessorDelegate <NSObject>

- (void)artifactProcessorDidProcessSnapshotContainer;
- (void)artifactProcessorDidShutdown;

@end

typedef void (^GTXArtifactProcessorReportFetchBlock)(GTXReport *report);

/**
* An artifact processor which can process artifacts on background threads.
*/
@interface GTXArtifactProcessor : NSObject

/**
* Use initWithChecks:delegate: instead.
*/
- (instancetype)init NS_UNAVAILABLE;

/**
* Initializes a new artifact processor to work with the given set of checks.
*
* @param checks The checks to be performed on the snapshots.
* @param delegate An optional delegate to recieve callback of checks processing.
*
* @return a new artifact processor.
*/
- (instancetype)initWithChecks:(NSArray<id<GTXChecking>> *)checks
delegate:(nullable id<GTXArtifactProcessorDelegate>)delegate;

/**
* Starts a background thread to process the submitted snapshots.
*/
- (void)startProcessing;

/**
* Stops the backgorund processing of snapshots, any snapshots submitted after this call may not
* be processed.
*/
- (void)stopProcessing;

/**
* Fetches the latest report held by the processor and invokes the given callback with it.
*
* @param fetchBlock A callback to invoke once the report is prepared.
*/
- (void)fetchLatestReportAsync:(GTXArtifactProcessorReportFetchBlock)fetchBlock;

/**
* Adds a snapshot container into the artifact processor's internal buffer for processing.
*
* @param container The snapshot container to be processed.
*
* @return @c YES if the container was successfully added, @c NO otherwise.
*/
- (BOOL)addSnapshotContainerForProcessing:(GTXSnapshotContainer *)container;

@end

NS_ASSUME_NONNULL_END
138 changes: 138 additions & 0 deletions Classes/GTXArtifactProcessor.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// Copyright 2019 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 "GTXArtifactProcessor.h"

#import <Foundation/Foundation.h>

#import "GTXAssertions.h"
#import "GTXSnapshotBuffer.h"

@implementation GTXArtifactProcessor {
NSArray<id<GTXChecking>> *_checks;
id<GTXArtifactProcessorDelegate> _delegate;
volatile BOOL _isShuttingDown;
GTXSnapshotBuffer *_buffer;
GTXReport *_report;

// GTXArtifactProcessor uses a command buffer model to deal with multi-threading: all
// processing and its associated tasks enqueue as commands on a command queue and are executed
// from it. @c _queueKey and @c _queueContext are used to ensure that commands related code is
// only invoked from the command queue context.
dispatch_queue_t _commandQueue;
void *_queueKey, *_queueContext;
}

- (instancetype)initWithChecks:(NSArray<id<GTXChecking>> *)checks
delegate:(id<GTXArtifactProcessorDelegate>)delegate {
self = [super init];
if (self) {
_checks = checks;
_delegate = delegate;
_buffer = [[GTXSnapshotBuffer alloc] init];
}
return self;
}

- (void)startProcessing {
GTX_ASSERT(!_commandQueue, @"GTXArtifactProcessor was already started");
_report = [[GTXReport alloc] init];
_commandQueue =
dispatch_queue_create("com.google.gtxilib.artifactprocessor", DISPATCH_QUEUE_SERIAL);
_queueKey = &_queueKey;
_queueContext = &_queueContext;
dispatch_queue_set_specific(_commandQueue, _queueKey, _queueContext, NULL);
}

- (void)stopProcessing {
__weak typeof(self) weakSelf = self;
dispatch_async(_commandQueue, ^{
[weakSelf gtx_commandForProcessorShutdown];
});
}

- (BOOL)addSnapshotContainerForProcessing:(GTXSnapshotContainer *)container {
if (_isShuttingDown) {
return NO;
}
[_buffer putSnapshotsContainer:container];
__weak typeof(self) wSelf = self;
dispatch_async(_commandQueue, ^{
[wSelf gtx_commandForProcessingNextSnapshot];
});
return YES;
}

- (void)fetchLatestReportAsync:(GTXArtifactProcessorReportFetchBlock)fetchBlock {
__weak typeof(self) weakSelf = self;
dispatch_async(_commandQueue, ^{
[weakSelf gtx_commandForReportFetch:fetchBlock];
});
}

#pragma mark - Artifact Processor Command Implementations

- (void)gtx_assertCallerIsCommandQueue {
void *context = dispatch_queue_get_specific(_commandQueue, _queueKey);
GTX_ASSERT(context == _queueContext, @"This method can only be executed from command queue.");
}

- (void)gtx_commandForProcessingNextSnapshot {
[self gtx_assertCallerIsCommandQueue];
if (_isShuttingDown) {
return;
}
GTXSnapshotContainer *container = [_buffer getNextSnapshotsContainer];
if (container) {
// Process this container and add errors to the report.
for (id<GTXChecking> check in _checks) {
if ([check respondsToSelector:@selector(performCheckOnSnapshot:addingErrorsToReport:)]) {
[check performCheckOnSnapshot:container addingErrorsToReport:_report];
// @TODO: Consider adding all passing elements to the report as well, it might be useful to
// look at all the elements that were scanned.
}
}
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf->_delegate artifactProcessorDidProcessSnapshotContainer];
}
});
}
}

- (void)gtx_commandForProcessorShutdown {
[self gtx_assertCallerIsCommandQueue];
_isShuttingDown = YES;
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf->_delegate artifactProcessorDidShutdown];
}
});
}

- (void)gtx_commandForReportFetch:(GTXArtifactProcessorReportFetchBlock)fetchBlock {
[self gtx_assertCallerIsCommandQueue];
GTXReport *reportCopy = [_report copy];
dispatch_async(dispatch_get_main_queue(), ^{
fetchBlock(reportCopy);
});
}

@end
Loading

0 comments on commit 42c7a1d

Please sign in to comment.