Simplify Interaction Base Class

This commit is contained in:
lawrencelomax 2016-02-08 08:07:03 +00:00
Родитель 31ac429167
Коммит 3c3adc0df5
12 изменённых файлов: 364 добавлений и 198 удалений

Просмотреть файл

@ -70,7 +70,6 @@
AA95175F1C15F54600A89CAD /* FBSimulatorHistoryGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = AA9516DB1C15F54600A89CAD /* FBSimulatorHistoryGenerator.m */; };
AA9517601C15F54600A89CAD /* FBSimulatorNotificationEventSink.h in Headers */ = {isa = PBXBuildFile; fileRef = AA9516DC1C15F54600A89CAD /* FBSimulatorNotificationEventSink.h */; settings = {ATTRIBUTES = (Public, ); }; };
AA9517611C15F54600A89CAD /* FBSimulatorNotificationEventSink.m in Sources */ = {isa = PBXBuildFile; fileRef = AA9516DD1C15F54600A89CAD /* FBSimulatorNotificationEventSink.m */; };
AA9517621C15F54600A89CAD /* FBInteraction+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AA9516DF1C15F54600A89CAD /* FBInteraction+Private.h */; settings = {ATTRIBUTES = (Public, ); }; };
AA9517631C15F54600A89CAD /* FBInteraction.h in Headers */ = {isa = PBXBuildFile; fileRef = AA9516E01C15F54600A89CAD /* FBInteraction.h */; settings = {ATTRIBUTES = (Public, ); }; };
AA9517641C15F54600A89CAD /* FBInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = AA9516E11C15F54600A89CAD /* FBInteraction.m */; };
AA9517651C15F54600A89CAD /* FBSimulatorInteraction+Agents.h in Headers */ = {isa = PBXBuildFile; fileRef = AA9516E21C15F54600A89CAD /* FBSimulatorInteraction+Agents.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -862,7 +861,6 @@
AA9516DB1C15F54600A89CAD /* FBSimulatorHistoryGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorHistoryGenerator.m; sourceTree = "<group>"; };
AA9516DC1C15F54600A89CAD /* FBSimulatorNotificationEventSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSimulatorNotificationEventSink.h; sourceTree = "<group>"; };
AA9516DD1C15F54600A89CAD /* FBSimulatorNotificationEventSink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorNotificationEventSink.m; sourceTree = "<group>"; };
AA9516DF1C15F54600A89CAD /* FBInteraction+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBInteraction+Private.h"; sourceTree = "<group>"; };
AA9516E01C15F54600A89CAD /* FBInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBInteraction.h; sourceTree = "<group>"; };
AA9516E11C15F54600A89CAD /* FBInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBInteraction.m; sourceTree = "<group>"; };
AA9516E21C15F54600A89CAD /* FBSimulatorInteraction+Agents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBSimulatorInteraction+Agents.h"; sourceTree = "<group>"; };
@ -1784,7 +1782,6 @@
children = (
AA9516E01C15F54600A89CAD /* FBInteraction.h */,
AA9516E11C15F54600A89CAD /* FBInteraction.m */,
AA9516DF1C15F54600A89CAD /* FBInteraction+Private.h */,
AA9516F11C15F54600A89CAD /* FBSimulatorInteraction.h */,
AA9516F21C15F54600A89CAD /* FBSimulatorInteraction.m */,
AA9516E21C15F54600A89CAD /* FBSimulatorInteraction+Agents.h */,
@ -1998,7 +1995,6 @@
AA9517991C15F54600A89CAD /* FBDispatchSourceNotifier.h in Headers */,
AA95178E1C15F54600A89CAD /* FBSimulatorApplication.h in Headers */,
AA9517851C15F54600A89CAD /* FBSimulatorPool.h in Headers */,
AA9517621C15F54600A89CAD /* FBInteraction+Private.h in Headers */,
AA9517511C15F54600A89CAD /* FBSimulatorConfiguration.h in Headers */,
AA0771F11C1ADFA300E7FD52 /* FBBinaryParser.h in Headers */,
AA9517471C15F54600A89CAD /* FBProcessLaunchConfiguration+Helpers.h in Headers */,

Просмотреть файл

@ -24,7 +24,6 @@
#import <FBSimulatorControl/FBFramebufferDebugWindow.h>
#import <FBSimulatorControl/FBFramebufferDelegate.h>
#import <FBSimulatorControl/FBFramebufferVideo.h>
#import <FBSimulatorControl/FBInteraction+Private.h>
#import <FBSimulatorControl/FBInteraction.h>
#import <FBSimulatorControl/FBJSONSerializationDescribeable.h>
#import <FBSimulatorControl/FBMutableSimulatorEventSink.h>

Просмотреть файл

@ -1,61 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <FBSimulatorControl/FBInteraction.h>
@interface FBInteraction ()
/**
The NSMutableArray<id<FBInteraction>> to be chained together when `performInteractionWithError:` is called.
*/
@property (nonatomic, strong) NSMutableArray *interactions;
/**
Chains an interaction using the provided block
@param block the block to perform the interaction with. Passes an NSError to return error information and the interaction for further chaining.
@return the reciever, for chaining.
*/
- (instancetype)interact:(BOOL (^)(NSError **error, id interaction))block;
/**
Fails the Interaction with the provided error.
@param error the error to fail the interaction with.
@return the reciever, for chaining.
*/
- (instancetype)failWith:(NSError *)error;
/**
Passes the interaction.
@return the reciever, for chaining.
*/
- (instancetype)succeed;
/**
Takes an NSArray<id<FBInteraction>> and returns an id<FBInteracton>.
Any failing interaction will terminate the chain.
@param interactions the interactions to chain together.
*/
+ (id<FBInteraction>)chainInteractions:(NSArray *)interactions;
@end
/**
Implementation of id<FBInteraction> using a block
*/
@interface FBInteraction_Block : NSObject<FBInteraction>
@property (nonatomic, copy) BOOL (^block)(NSError **error);
+ (id<FBInteraction>)interactionWithBlock:( BOOL(^)(NSError **error) )block;
@end

Просмотреть файл

@ -12,7 +12,7 @@
#import <FBSimulatorControl/FBInteraction.h>
/**
Represents a failable transaction involving a Simulator.
Represents a Synchronous Action that can Succed or Fail.
*/
@protocol FBInteraction <NSObject>
@ -27,23 +27,42 @@
@end
/**
Overridable class for providing an interaction-based API.
A Concrete FBInteraction that can be subclassed to provide a chainable API.
*/
@interface FBInteraction : NSObject <FBInteraction>
@interface FBInteraction : NSObject <FBInteraction, NSCopying>
#pragma mark Initializer
/**
Retries the last chained interaction by `retries`, if it fails.
Creates a Subclassable Interaction
@param interaction the underlying interaction.
@return a subclassable FBInteraction Instance.
*/
- (instancetype)initWithInteraction:(id<FBInteraction>)interaction;
@param retries the number of times to retry if the prior interaction fails.
#pragma mark Properties
/**
The Base Interaction.
*/
@property (nonatomic, strong, readonly) id<FBInteraction> interaction;
#pragma mark Chaining
/**
Chains an interaction using the provided block.
@param block the block to perform the interaction with. Passes an NSError to return error information and the Interaction Subclass for further chaining.
@return the reciever, for chaining.
*/
- (instancetype)retry:(NSUInteger)retries;
- (instancetype)interact:(BOOL (^)(NSError **error, id interaction))block;
/**
Ignores any failure that occurs in the last interaction if any occured.
Chains an interaction that will allways succeed.
@return the reciever, for chaining.
*/
- (instancetype)ignoreFailure;
- (instancetype)succeed;
@end

Просмотреть файл

@ -8,133 +8,93 @@
*/
#import "FBInteraction.h"
#import "FBInteraction+Private.h"
#import "FBSimulatorError.h"
@implementation FBInteraction
@interface FBInteraction ()
- (instancetype)init
#pragma mark Primitives
/**
Chains an interaction using the provided block
@param block the block to perform the interaction with. Passes an NSError to return error information and the interaction for further chaining.
@return the reciever, for chaining.
*/
+ (id<FBInteraction>)interact:(BOOL (^)(NSError **error))block;
/**
Creates an Interaction that allways Fails.
@param error the error to fail the interaction with.
@return an Interaction that allways Fails.
*/
+ (id<FBInteraction>)fail:(NSError *)error;
/**
Creates an Interaction that always Succeeds.
@return an Interaction that always Succeeds.
*/
+ (id<FBInteraction>)succeed;
/**
Creates an Interaction that will retry a base interaction a number of times, before failing.
@param retries the number of retries, must be 1 or greater.
@param interaction the base interaction to retry.
@return a retrying interaction.
*/
+ (id<FBInteraction>)retry:(NSUInteger)retries interaction:(id<FBInteraction>)interaction;
/**
Ignores any failure that occurs to the base interaction.
@param interaction the interaction to attempt.
@return an interaction that allways succeds.
*/
+ (id<FBInteraction>)ignoreFailure:(id<FBInteraction>)interaction;
/**
Takes an NSArray<id<FBInteraction>> and returns an id<FBInteracton>.
Any failing interaction will terminate the chain.
@param interactions the interactions to chain together.
*/
+ (id<FBInteraction>)sequence:(NSArray *)interactions;
/**
Joins to interactions together.
Equivalent to [FBInteraction sequence:@[first, second]]
@param first the interaction to perform first.
@param second the interaction to perform second.
@return a chained interaction.
*/
+ (id<FBInteraction>)first:(id<FBInteraction>)first second:(id<FBInteraction>)second;
@end
@interface FBInteraction_Block : NSObject <FBInteraction>
@property (nonatomic, copy, readonly) BOOL (^block)(NSError **error);
@end
@implementation FBInteraction_Block
- (instancetype)initWithBlock:( BOOL(^)(NSError **error) )block
{
self = [super init];
if (!self) {
return nil;
}
_interactions = [NSMutableArray array];
_block = block;
return self;
}
+ (id<FBInteraction>)chainInteractions:(NSArray *)interactions
{
return [FBInteraction_Block interactionWithBlock:^ BOOL (NSError **error) {
for (id<FBInteraction> interaction in interactions) {
NSError *innerError = nil;
if (![interaction performInteractionWithError:&innerError]) {
return [FBSimulatorError failBoolWithError:innerError errorOut:error];
}
}
return YES;
}];
}
- (instancetype)interact:(BOOL (^)(NSError **error, id interaction))block
{
NSParameterAssert(block);
__weak id weakInteraction = self;
return [self addInteraction:[FBInteraction_Block interactionWithBlock:^ BOOL (NSError **error) {
__strong id interaction = weakInteraction;
return block(error, interaction);
}]];
}
- (instancetype)failWith:(NSError *)error
{
NSParameterAssert(error);
return [self interact:^ BOOL (NSError **errorPtr, id _) {
NSCParameterAssert(errorPtr);
*errorPtr = error;
return NO;
}];
}
- (instancetype)succeed
{
return [self interact:^ BOOL (NSError **_, id __) {
return YES;
}];
}
- (instancetype)addInteraction:(id<FBInteraction>)interaction
{
[self.interactions addObject:interaction];
return self;
}
- (instancetype)retry:(NSUInteger)retries
{
NSParameterAssert(retries > 1);
return [self replaceLastInteraction:^ id<FBInteraction> (id<FBInteraction> interaction) {
return [FBInteraction_Block interactionWithBlock:^ BOOL (NSError **error) {
NSError *innerError = nil;
for (NSUInteger index = 0; index < retries; index++) {
if ([interaction performInteractionWithError:&innerError]) {
return YES;
}
}
return [[[FBSimulatorError describeFormat:@"Failed interaction after %ld retries", retries] causedBy:innerError] failBool:error];
}];
}];
}
- (instancetype)ignoreFailure
{
return [self replaceLastInteraction:^ id<FBInteraction> (id<FBInteraction> interaction) {
return [FBInteraction_Block interactionWithBlock:^ BOOL (NSError **error) {
NSError *innerError = nil;
[interaction performInteractionWithError:&innerError];
return YES;
}];
}];
}
- (id<FBInteraction>)build
{
return [FBInteraction chainInteractions:[self.interactions copy]];
}
- (BOOL)performInteractionWithError:(NSError **)error
{
return [[self build] performInteractionWithError:error];
}
#pragma mark Private
- (instancetype)replaceLastInteraction:( id<FBInteraction>(^)(id<FBInteraction> interaction) )block
{
NSParameterAssert(self.interactions.count > 0);
NSUInteger interactionIndex = self.interactions.count - 1;
id<FBInteraction> interaction = self.interactions[interactionIndex];
id<FBInteraction> nextInteraction = block(interaction);
[self.interactions replaceObjectAtIndex:interactionIndex withObject:nextInteraction];
return self;
}
@end
@implementation FBInteraction_Block
+ (id<FBInteraction>)interactionWithBlock:( BOOL(^)(NSError **error) )block
{
FBInteraction_Block *interaction = [self new];
interaction.block = block;
return interaction;
}
- (BOOL)performInteractionWithError:(NSError **)error
{
NSError *innerError = nil;
@ -146,3 +106,222 @@
}
@end
@interface FBInteraction_Sequence : NSObject <FBInteraction>
@property (nonatomic, copy, readonly) NSArray *interactions;
@end
@implementation FBInteraction_Sequence
- (instancetype)initWithInteractions:(NSArray *)interactions
{
self = [super init];
if (!self) {
return nil;
}
_interactions = interactions;
return self;
}
- (BOOL)performInteractionWithError:(NSError **)error
{
for (id<FBInteraction> interaction in self.interactions) {
NSError *innerError = nil;
if (![interaction performInteractionWithError:&innerError]) {
return [FBSimulatorError failBoolWithError:innerError errorOut:error];
}
}
return YES;
}
@end
@interface FBInteraction_Success : NSObject <FBInteraction>
@end
@implementation FBInteraction_Success
- (BOOL)performInteractionWithError:(NSError **)error
{
return YES;
}
@end
@interface FBInteraction_Failure : NSObject <FBInteraction>
@property (nonnull, strong, readonly) NSError *error;
@end
@implementation FBInteraction_Failure
- (instancetype)initWithError:(NSError *)error
{
self = [super init];
if (!self) {
return nil;
}
_error = error;
return self;
}
- (BOOL)performInteractionWithError:(NSError **)errorPtr
{
if (errorPtr) {
*errorPtr = self.error;
}
return NO;
}
@end
@interface FBInteraction_Retrying : NSObject <FBInteraction>
@property (nonatomic, strong, readonly) id<FBInteraction> interaction;
@property (nonatomic, assign, readonly) NSUInteger retries;
@end
@implementation FBInteraction_Retrying
- (instancetype)initWithInteraction:(id<FBInteraction>)interaction retries:(NSUInteger)retries
{
self = [super init];
if (!self) {
return nil;
}
_interaction = interaction;
_retries = retries;
return self;
}
- (BOOL)performInteractionWithError:(NSError **)error
{
NSError *innerError = nil;
for (NSUInteger index = 0; index < self.retries; index++) {
if ([self.interaction performInteractionWithError:&innerError]) {
return YES;
}
}
return [[[FBSimulatorError
describeFormat:@"Failed interaction after %ld retries", self.retries]
causedBy:innerError]
failBool:error];
}
@end
@implementation FBInteraction
#pragma mark Initializers
- (instancetype)init
{
return [self initWithInteraction:nil];
}
- (instancetype)initWithInteraction:(id<FBInteraction>)interaction
{
self = [super init];
if (!self) {
return nil;
}
_interaction = interaction ?: FBInteraction.succeed;
return self;
}
#pragma mark NSCopying
- (instancetype)copyWithZone:(NSZone *)zone
{
return [[self.class alloc] initWithInteraction:self.interaction];
}
#pragma mark Primitives
+ (id<FBInteraction>)interact:(BOOL (^)(NSError **error))block
{
NSParameterAssert(block);
return [[FBInteraction_Block alloc] initWithBlock:block];
}
+ (id<FBInteraction>)fail:(NSError *)error
{
NSParameterAssert(error);
return [[FBInteraction_Failure alloc] initWithError:error];
}
+ (id<FBInteraction>)succeed
{
return [FBInteraction_Success new];
}
+ (id<FBInteraction>)retry:(NSUInteger)retries interaction:(id<FBInteraction>)interaction;
{
NSParameterAssert(retries > 1);
NSParameterAssert(interaction);
return [[FBInteraction_Retrying alloc] initWithInteraction:interaction retries:retries];
}
+ (id<FBInteraction>)ignoreFailure:(id<FBInteraction>)interaction
{
NSParameterAssert(interaction);
return [self interact:^ BOOL (NSError **error) {
NSError *innerError = nil;
[interaction performInteractionWithError:&innerError];
return YES;
}];
}
+ (id<FBInteraction>)sequence:(NSArray *)interactions
{
return [[FBInteraction_Sequence alloc] initWithInteractions:interactions];
}
+ (id<FBInteraction>)first:(id<FBInteraction>)first second:(id<FBInteraction>)second
{
NSParameterAssert(first);
NSParameterAssert(second);
return [self sequence:@[first, second]];
}
#pragma mark Chainable Interactions
- (instancetype)interact:(BOOL (^)(NSError **error, id interaction))block
{
id<FBInteraction> next = [FBInteraction interact:^ BOOL (NSError **error) {
return block(error, self);
}];
FBInteraction *interaction = [self copy];
interaction->_interaction = [FBInteraction first:self.interaction second:next];
return interaction;
}
- (instancetype)succeed
{
return self;
}
#pragma mark FBInteraction
- (BOOL)performInteractionWithError:(NSError **)error
{
return [self.interaction performInteractionWithError:error];
}
@end

Просмотреть файл

@ -11,7 +11,6 @@
#import <CoreSimulator/SimDevice.h>
#import "FBInteraction+Private.h"
#import "FBProcessInfo.h"
#import "FBProcessLaunchConfiguration+Helpers.h"
#import "FBProcessLaunchConfiguration.h"

Просмотреть файл

@ -11,7 +11,6 @@
#import <CoreSimulator/SimDevice.h>
#import "FBInteraction+Private.h"
#import "FBProcessInfo.h"
#import "FBProcessLaunchConfiguration+Helpers.h"
#import "FBProcessLaunchConfiguration.h"

Просмотреть файл

@ -19,7 +19,6 @@
#import <SimulatorKit/SimDeviceFramebufferService.h>
#import "FBCollectionDescriptions.h"
#import "FBInteraction+Private.h"
#import "FBProcessInfo.h"
#import "FBProcessLaunchConfiguration.h"
#import "FBProcessQuery+Simulators.h"

Просмотреть файл

@ -14,7 +14,10 @@
@interface FBSimulatorInteraction ()
@property (nonatomic, strong) FBSimulator *simulator;
/**
The Simulator belonging to the Interaction.
*/
@property (nonatomic, strong, readonly) FBSimulator *simulator;
/**
Chains an interaction on an process, for the given application.
@ -34,6 +37,23 @@
*/
- (instancetype)binary:(FBSimulatorBinary *)binary interact:(BOOL (^)(NSError **error, FBSimulator *simulator, FBProcessInfo *process))block;
/**
Interact with the Simulator.
@param block the block to execute with the Simulator.
@return the reciever, for chaining.
*/
- (instancetype)interactWithSimulator:(BOOL (^)(NSError **error, FBSimulator *simulator))block;
/**
Interact with the Simulator. Will ensure that the Simulator is in the appropriate state.
@param state the state to verify.
@param block the block to execute with the Simulator.
@return the reciever, for chaining.
*/
- (instancetype)interactWithSimulatorAtState:(FBSimulatorState)state block:(BOOL (^)(NSError **error, FBSimulator *simulator))block;
/**
Interact with a Shutdown Simulator. Will ensure that the Simulator is in the appropriate state.

Просмотреть файл

@ -11,7 +11,6 @@
#import <CoreSimulator/SimDevice.h>
#import "FBInteraction+Private.h"
#import "FBSimulator.h"
#import "FBSimulatorApplication.h"
#import "FBSimulatorError.h"

Просмотреть файл

@ -11,7 +11,6 @@
#import <CoreSimulator/SimDevice.h>
#import "FBInteraction+Private.h"
#import "FBProcessLaunchConfiguration+Helpers.h"
#import "FBSimDeviceWrapper.h"
#import "FBSimulator+Helpers.h"

Просмотреть файл

@ -13,7 +13,6 @@
#import <CoreSimulator/SimDevice.h>
#import "FBCollectionDescriptions.h"
#import "FBInteraction+Private.h"
#import "FBProcessLaunchConfiguration.h"
#import "FBProcessQuery+Simulators.h"
#import "FBSimulator+Helpers.h"
@ -32,11 +31,31 @@
@implementation FBSimulatorInteraction
#pragma mark Initializers
+ (instancetype)withSimulator:(FBSimulator *)simulator
{
FBSimulatorInteraction *interaction = [self new];
interaction.simulator = simulator;
return interaction;
return [[self alloc] initWithInteraction:nil simulator:simulator];
}
- (instancetype)initWithInteraction:(id<FBInteraction>)interaction simulator:(FBSimulator *)simulator
{
self = [super initWithInteraction:interaction];
if (!self) {
return nil;
}
_simulator = simulator;
return self;
}
#pragma mark NSCopying
- (instancetype)copyWithZone:(NSZone *)zone
{
FBSimulatorInteraction *interaction = [super copyWithZone:zone];
interaction->_simulator = self.simulator;
return self;
}
#pragma mark Private