1902 lines
117 KiB
Objective-C
1902 lines
117 KiB
Objective-C
/*
|
|
Copyright (c) 2015-2016, Ricardo Sánchez-Sáez.
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation and/or
|
|
other materials provided with the distribution.
|
|
|
|
3. Neither the name of the copyright holder(s) nor the names of any contributors
|
|
may be used to endorse or promote products derived from this software without
|
|
specific prior written permission. No license is granted to the trademarks of
|
|
the copyright holders even if such marks are included in this software.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
@import XCTest;
|
|
@import ResearchKit_Private;
|
|
@import ResearchKitUI;
|
|
@import ResearchKitActiveTask;
|
|
|
|
@interface ORKTaskTests : XCTestCase
|
|
|
|
@end
|
|
|
|
@interface MethodObject : NSObject
|
|
@property (nonatomic) NSString *selectorName;
|
|
@property (nonatomic) NSArray *arguments;
|
|
@end
|
|
|
|
@interface TestTaskViewControllerDelegate : NSObject <ORKTaskViewControllerDelegate>
|
|
@property (nonatomic) NSMutableArray <MethodObject *> *methodCalled;
|
|
@end
|
|
|
|
@interface MockTaskViewController : ORKTaskViewController
|
|
@property (nonatomic) NSMutableArray <MethodObject *> *methodCalled;
|
|
@property (nonatomic, nullable) NSNumber *overrideHasSaveableResults;
|
|
@end
|
|
|
|
@interface ORKTaskViewController (Testing)
|
|
- (BOOL)hasSaveableResults;
|
|
- (BOOL)isSafeToSkipConfirmation;
|
|
@end
|
|
|
|
@interface ORKReviewStep (Testing)
|
|
- (BOOL)isStandalone;
|
|
@end
|
|
|
|
@implementation ORKTaskTests {
|
|
NSArray *_orderedTaskStepIdentifiers;
|
|
NSArray *_orderedTaskSteps;
|
|
ORKOrderedTask *_orderedTask;
|
|
|
|
NSArray *_navigableOrderedTaskStepIdentifiers;
|
|
NSArray *_navigableOrderedTaskSteps;
|
|
NSMutableDictionary *_stepNavigationRules;
|
|
ORKNavigableOrderedTask *_navigableOrderedTask;
|
|
}
|
|
|
|
ORKDefineStringKey(HeadacheChoiceValue);
|
|
ORKDefineStringKey(DizzinessChoiceValue);
|
|
ORKDefineStringKey(NauseaChoiceValue);
|
|
|
|
ORKDefineStringKey(SymptomStepIdentifier);
|
|
ORKDefineStringKey(SeverityStepIdentifier);
|
|
ORKDefineStringKey(BlankStepIdentifier);
|
|
ORKDefineStringKey(SevereHeadacheStepIdentifier);
|
|
ORKDefineStringKey(LightHeadacheStepIdentifier);
|
|
ORKDefineStringKey(OtherSymptomStepIdentifier);
|
|
ORKDefineStringKey(EndStepIdentifier);
|
|
ORKDefineStringKey(BlankBStepIdentifier);
|
|
|
|
ORKDefineStringKey(OrderedTaskIdentifier);
|
|
ORKDefineStringKey(NavigableOrderedTaskIdentifier);
|
|
|
|
- (void)generateTaskSteps:(out NSArray **)outSteps stepIdentifiers:(out NSArray **)outStepIdentifiers {
|
|
if (outSteps == NULL || outStepIdentifiers == NULL) {
|
|
return;
|
|
}
|
|
|
|
NSMutableArray *stepIdentifiers = [NSMutableArray new];
|
|
NSMutableArray *steps = [NSMutableArray new];
|
|
|
|
ORKAnswerFormat *answerFormat = nil;
|
|
NSString *stepIdentifier = nil;
|
|
ORKStep *step = nil;
|
|
|
|
NSArray *textChoices =
|
|
@[
|
|
[ORKTextChoice choiceWithText:@"Headache" value:HeadacheChoiceValue],
|
|
[ORKTextChoice choiceWithText:@"Dizziness" value:DizzinessChoiceValue],
|
|
[ORKTextChoice choiceWithText:@"Nausea" value:NauseaChoiceValue]
|
|
];
|
|
|
|
answerFormat = [ORKAnswerFormat choiceAnswerFormatWithStyle:ORKChoiceAnswerStyleSingleChoice
|
|
textChoices:textChoices];
|
|
stepIdentifier = SymptomStepIdentifier;
|
|
step = [ORKQuestionStep questionStepWithIdentifier:stepIdentifier title:@"Survey" question:@"What is your symptom?" answer:answerFormat];
|
|
step.optional = NO;
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
answerFormat = [ORKAnswerFormat booleanAnswerFormat];
|
|
stepIdentifier = SeverityStepIdentifier;
|
|
step = [ORKQuestionStep questionStepWithIdentifier:stepIdentifier title:@"Survey" question:@"Does your symptom interferes with your daily life?" answer:answerFormat];
|
|
step.optional = NO;
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
stepIdentifier = BlankStepIdentifier;
|
|
step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
|
|
step.title = @"This step is intentionally left blank (you should not see it)";
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
stepIdentifier = SevereHeadacheStepIdentifier;
|
|
step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
|
|
step.title = @"You have a severe headache";
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
stepIdentifier = LightHeadacheStepIdentifier;
|
|
step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
|
|
step.title = @"You have a light headache";
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
stepIdentifier = OtherSymptomStepIdentifier;
|
|
step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
|
|
step.title = @"You have other symptom";
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
stepIdentifier = EndStepIdentifier;
|
|
step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
|
|
step.title = @"You have finished the task";
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
stepIdentifier = BlankBStepIdentifier;
|
|
step = [[ORKInstructionStep alloc] initWithIdentifier:stepIdentifier];
|
|
step.title = @"This step is intentionally left blank (you should not see it)";
|
|
[stepIdentifiers addObject:stepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
*outSteps = steps;
|
|
*outStepIdentifiers = stepIdentifiers;
|
|
}
|
|
|
|
- (void)setUpOrderedTask {
|
|
NSArray *orderedTaskSteps = nil;
|
|
NSArray *orderedTaskStepIdentifiers = nil;
|
|
[self generateTaskSteps:&orderedTaskSteps stepIdentifiers:&orderedTaskStepIdentifiers];
|
|
_orderedTaskSteps = orderedTaskSteps;
|
|
_orderedTaskStepIdentifiers = orderedTaskStepIdentifiers;
|
|
|
|
_orderedTask = [[ORKOrderedTask alloc] initWithIdentifier:OrderedTaskIdentifier
|
|
steps:ORKArrayCopyObjects(_orderedTaskSteps)]; // deep copy to test step copying and equality
|
|
}
|
|
|
|
- (void)setUpNavigableOrderedTask {
|
|
ORKResultSelector *resultSelector = nil;
|
|
NSArray *navigableOrderedTaskSteps = nil;
|
|
NSArray *navigableOrderedTaskStepIdentifiers = nil;
|
|
[self generateTaskSteps:&navigableOrderedTaskSteps stepIdentifiers:&navigableOrderedTaskStepIdentifiers];
|
|
_navigableOrderedTaskSteps = navigableOrderedTaskSteps;
|
|
_navigableOrderedTaskStepIdentifiers = navigableOrderedTaskStepIdentifiers;
|
|
|
|
_navigableOrderedTask = [[ORKNavigableOrderedTask alloc] initWithIdentifier:NavigableOrderedTaskIdentifier
|
|
steps:ORKArrayCopyObjects(_navigableOrderedTaskSteps)]; // deep copy to test step copying and equality
|
|
|
|
// Build navigation rules
|
|
_stepNavigationRules = [NSMutableDictionary new];
|
|
// Individual predicates
|
|
|
|
// User chose headache at the symptom step
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:SymptomStepIdentifier];
|
|
NSPredicate *predicateHeadache = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValue:HeadacheChoiceValue];
|
|
// Equivalent to:
|
|
// [NSPredicate predicateWithFormat:
|
|
// @"SUBQUERY(SELF, $x, $x.identifier like 'symptom' \
|
|
// AND SUBQUERY($x.answer, $y, $y like 'headache').@count > 0).@count > 0"];
|
|
|
|
// User didn't chose headache at the symptom step
|
|
NSPredicate *predicateNotHeadache = [NSCompoundPredicate notPredicateWithSubpredicate:predicateHeadache];
|
|
|
|
// User chose YES at the severity step
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:SeverityStepIdentifier];
|
|
NSPredicate *predicateSevereYes = [ORKResultPredicate predicateForBooleanQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:YES];
|
|
// Equivalent to:
|
|
// [NSPredicate predicateWithFormat:
|
|
// @"SUBQUERY(SELF, $x, $x.identifier like 'severity' AND $x.answer == YES).@count > 0"];
|
|
|
|
// User chose NO at the severity step
|
|
NSPredicate *predicateSevereNo = [ORKResultPredicate predicateForBooleanQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:NO];
|
|
|
|
|
|
// From the "symptom" step, go to "other_symptom" is user didn't chose headache.
|
|
// Otherwise, default to going to next step (when the defaultStepIdentifier argument is omitted,
|
|
// the regular ORKOrderedTask order applies).
|
|
NSMutableArray *resultPredicates = [NSMutableArray new];
|
|
NSMutableArray *destinationStepIdentifiers = [NSMutableArray new];
|
|
|
|
[resultPredicates addObject:predicateNotHeadache];
|
|
[destinationStepIdentifiers addObject:OtherSymptomStepIdentifier];
|
|
|
|
ORKPredicateStepNavigationRule *predicateRule =
|
|
[[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:resultPredicates
|
|
destinationStepIdentifiers:destinationStepIdentifiers];
|
|
|
|
[_navigableOrderedTask setNavigationRule:predicateRule forTriggerStepIdentifier:SymptomStepIdentifier];
|
|
_stepNavigationRules[SymptomStepIdentifier] = [predicateRule copy];
|
|
|
|
// From the "severity" step, go to "severe_headache" or "light_headache" depending on the user answer
|
|
resultPredicates = [NSMutableArray new];
|
|
destinationStepIdentifiers = [NSMutableArray new];
|
|
|
|
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateHeadache, predicateSevereYes]];
|
|
[resultPredicates addObject:predicate];
|
|
[destinationStepIdentifiers addObject:SevereHeadacheStepIdentifier];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateHeadache, predicateSevereNo]];
|
|
[resultPredicates addObject:predicate];
|
|
[destinationStepIdentifiers addObject:LightHeadacheStepIdentifier];
|
|
|
|
predicateRule =
|
|
[[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:resultPredicates
|
|
destinationStepIdentifiers:destinationStepIdentifiers
|
|
defaultStepIdentifier:OtherSymptomStepIdentifier];
|
|
|
|
[_navigableOrderedTask setNavigationRule:predicateRule forTriggerStepIdentifier:SeverityStepIdentifier];
|
|
_stepNavigationRules[SeverityStepIdentifier] = [predicateRule copy];
|
|
|
|
|
|
// Add end direct rules to skip unneeded steps
|
|
ORKDirectStepNavigationRule *directRule = nil;
|
|
|
|
directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:EndStepIdentifier];
|
|
|
|
[_navigableOrderedTask setNavigationRule:directRule forTriggerStepIdentifier:SevereHeadacheStepIdentifier];
|
|
[_navigableOrderedTask setNavigationRule:directRule forTriggerStepIdentifier:LightHeadacheStepIdentifier];
|
|
[_navigableOrderedTask setNavigationRule:directRule forTriggerStepIdentifier:OtherSymptomStepIdentifier];
|
|
|
|
_stepNavigationRules[SevereHeadacheStepIdentifier] = [directRule copy];
|
|
_stepNavigationRules[LightHeadacheStepIdentifier] = [directRule copy];
|
|
_stepNavigationRules[OtherSymptomStepIdentifier] = [directRule copy];
|
|
|
|
directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:ORKNullStepIdentifier];
|
|
[_navigableOrderedTask setNavigationRule:directRule forTriggerStepIdentifier:EndStepIdentifier];
|
|
_stepNavigationRules[EndStepIdentifier] = [directRule copy];
|
|
}
|
|
|
|
typedef NS_OPTIONS(NSUInteger, TestsTaskResultOptions) {
|
|
TestsTaskResultOptionSymptomHeadache = 1 << 0,
|
|
TestsTaskResultOptionSymptomDizziness = 1 << 1,
|
|
TestsTaskResultOptionSymptomNausea = 1 << 2,
|
|
|
|
TestsTaskResultOptionSeverityYes = 1 << 3,
|
|
TestsTaskResultOptionSeverityNo = 1 << 4
|
|
};
|
|
|
|
- (ORKTaskResult *)getResultTreeWithTaskIdentifier:(NSString *)taskIdentifier resultOptions:(TestsTaskResultOptions)resultOptions {
|
|
if ( ((resultOptions & TestsTaskResultOptionSymptomDizziness) || (resultOptions & TestsTaskResultOptionSymptomNausea)) && ((resultOptions & TestsTaskResultOptionSeverityYes) || (resultOptions & TestsTaskResultOptionSeverityNo)) ) {
|
|
@throw [NSException exceptionWithName:NSGenericException reason:@"You can only add a severity result for the headache symptom" userInfo:nil];
|
|
}
|
|
|
|
NSMutableArray *stepResults = [NSMutableArray new];
|
|
|
|
ORKQuestionResult *questionResult = nil;
|
|
ORKStepResult *stepResult = nil;
|
|
NSString *stepIdentifier = nil;
|
|
|
|
if (resultOptions & (TestsTaskResultOptionSymptomHeadache | TestsTaskResultOptionSymptomDizziness | TestsTaskResultOptionSymptomNausea)) {
|
|
stepIdentifier = SymptomStepIdentifier;
|
|
questionResult = [[ORKChoiceQuestionResult alloc] initWithIdentifier:stepIdentifier];
|
|
if (resultOptions & TestsTaskResultOptionSymptomHeadache) {
|
|
questionResult.answer = @[HeadacheChoiceValue];
|
|
} else if (resultOptions & TestsTaskResultOptionSymptomDizziness) {
|
|
questionResult.answer = @[DizzinessChoiceValue];
|
|
} else if (resultOptions & TestsTaskResultOptionSymptomNausea) {
|
|
questionResult.answer = @[NauseaChoiceValue];
|
|
}
|
|
questionResult.questionType = ORKQuestionTypeSingleChoice;
|
|
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:stepIdentifier results:@[questionResult]];
|
|
[stepResults addObject:stepResult];
|
|
|
|
if (resultOptions & (TestsTaskResultOptionSymptomDizziness | TestsTaskResultOptionSymptomNausea)) {
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:OtherSymptomStepIdentifier results:nil];
|
|
[stepResults addObject:stepResult];
|
|
}
|
|
}
|
|
|
|
if (resultOptions & (TestsTaskResultOptionSeverityYes | TestsTaskResultOptionSeverityNo)) {
|
|
stepIdentifier = SeverityStepIdentifier;
|
|
questionResult = [[ORKBooleanQuestionResult alloc] initWithIdentifier:stepIdentifier];
|
|
if (resultOptions & TestsTaskResultOptionSeverityYes) {
|
|
questionResult.answer = @(YES);
|
|
} else if (resultOptions & TestsTaskResultOptionSeverityNo) {
|
|
questionResult.answer = @(NO);
|
|
}
|
|
questionResult.questionType = ORKQuestionTypeSingleChoice;
|
|
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:stepIdentifier results:@[questionResult]];
|
|
[stepResults addObject:stepResult];
|
|
|
|
|
|
if (resultOptions & TestsTaskResultOptionSeverityYes) {
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:SevereHeadacheStepIdentifier results:nil];
|
|
[stepResults addObject:stepResult];
|
|
} else if (resultOptions & TestsTaskResultOptionSeverityNo) {
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:LightHeadacheStepIdentifier results:nil];
|
|
[stepResults addObject:stepResult];
|
|
}
|
|
}
|
|
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:EndStepIdentifier results:nil];
|
|
[stepResults addObject:stepResult];
|
|
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:taskIdentifier
|
|
taskRunUUID:[NSUUID UUID]
|
|
outputDirectory:[NSURL fileURLWithPath:NSTemporaryDirectory()]];
|
|
taskResult.results = stepResults;
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
[self setUpOrderedTask];
|
|
[self setUpNavigableOrderedTask];
|
|
}
|
|
|
|
- (void)testOrderedTask {
|
|
ORKTaskResult *mockTaskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:_orderedTask.identifier taskRunUUID:[NSUUID UUID] outputDirectory:nil];
|
|
|
|
XCTAssertEqualObjects(_orderedTask.identifier, OrderedTaskIdentifier);
|
|
XCTAssertEqualObjects(_orderedTask.steps, _orderedTaskSteps);
|
|
|
|
NSUInteger expectedTotalProgress = _orderedTaskSteps.count;
|
|
|
|
for (ORKStep *step in _orderedTaskSteps) {
|
|
ORKTaskProgress currentProgress = [_orderedTask progressOfCurrentStep:step withResult:mockTaskResult];
|
|
if (!currentProgress.shouldBePresented) {
|
|
expectedTotalProgress -= 1;
|
|
}
|
|
}
|
|
|
|
for (NSUInteger stepIndex = 0; stepIndex < _orderedTaskStepIdentifiers.count; stepIndex++) {
|
|
ORKStep *currentStep = _orderedTaskSteps[stepIndex];
|
|
XCTAssertEqualObjects(currentStep, [_orderedTask stepWithIdentifier:_orderedTaskStepIdentifiers[stepIndex]]);
|
|
|
|
ORKTaskProgress currentProgress = [_orderedTask progressOfCurrentStep:currentStep withResult:mockTaskResult];
|
|
|
|
if (currentProgress.shouldBePresented) {
|
|
const NSUInteger expectedCurrentProgress = stepIndex;
|
|
XCTAssertEqual(currentProgress.total, expectedTotalProgress);
|
|
XCTAssertEqual(currentProgress.current, expectedCurrentProgress);
|
|
}
|
|
|
|
NSString *expectedPreviousStep = (stepIndex != 0) ? _orderedTaskSteps[stepIndex - 1] : nil;
|
|
NSString *expectedNextStep = (stepIndex < _orderedTaskStepIdentifiers.count - 1) ? _orderedTaskSteps[stepIndex + 1] : nil;
|
|
XCTAssertEqualObjects(expectedPreviousStep, [_orderedTask stepBeforeStep:currentStep withResult:mockTaskResult]);
|
|
XCTAssertEqualObjects(expectedNextStep, [_orderedTask stepAfterStep:currentStep withResult:mockTaskResult]);
|
|
}
|
|
|
|
// Test duplicate step identifier validation
|
|
XCTAssertNoThrow([_orderedTask validateParameters]);
|
|
|
|
NSMutableArray *steps = [[NSMutableArray alloc] initWithArray:ORKArrayCopyObjects(_orderedTaskSteps)];
|
|
ORKStep *step = [[ORKInstructionStep alloc] initWithIdentifier:BlankStepIdentifier];
|
|
[steps addObject:step];
|
|
|
|
XCTAssertThrows([[ORKOrderedTask alloc] initWithIdentifier:OrderedTaskIdentifier
|
|
steps:steps]);
|
|
}
|
|
|
|
#define getIndividualNavigableOrderedTaskSteps() \
|
|
__unused ORKStep *symptomStep = _navigableOrderedTaskSteps[0];\
|
|
__unused ORKStep *severityStep = _navigableOrderedTaskSteps[1];\
|
|
__unused ORKStep *blankStep = _navigableOrderedTaskSteps[2];\
|
|
__unused ORKStep *severeHeadacheStep = _navigableOrderedTaskSteps[3];\
|
|
__unused ORKStep *lightHeadacheStep = _navigableOrderedTaskSteps[4];\
|
|
__unused ORKStep *otherSymptomStep = _navigableOrderedTaskSteps[5];\
|
|
__unused ORKStep *endStep = _navigableOrderedTaskSteps[6];
|
|
|
|
BOOL (^testStepAfterStep)(ORKNavigableOrderedTask *, ORKTaskResult *, ORKStep *, ORKStep *) = ^BOOL(ORKNavigableOrderedTask *task, ORKTaskResult *taskResult, ORKStep *fromStep, ORKStep *expectedStep) {
|
|
ORKStep *testedStep = [task stepAfterStep:fromStep withResult:taskResult];
|
|
return (testedStep == nil && expectedStep == nil) || [testedStep isEqual:expectedStep];
|
|
};
|
|
|
|
BOOL (^testStepBeforeStep)(ORKNavigableOrderedTask *, ORKTaskResult *, ORKStep *, ORKStep *) = ^BOOL(ORKNavigableOrderedTask *task, ORKTaskResult *taskResult, ORKStep *fromStep, ORKStep *expectedStep) {
|
|
ORKStep *testedStep = [task stepBeforeStep:fromStep withResult:taskResult];
|
|
return (testedStep == nil && expectedStep == nil) || [testedStep isEqual:expectedStep];
|
|
};
|
|
|
|
- (void)testNavigableOrderedTask {
|
|
XCTAssertEqualObjects(_navigableOrderedTask.identifier, NavigableOrderedTaskIdentifier);
|
|
XCTAssertEqualObjects(_navigableOrderedTask.steps, _navigableOrderedTaskSteps);
|
|
XCTAssertEqualObjects(_navigableOrderedTask.stepNavigationRules, _stepNavigationRules);
|
|
|
|
for (NSString *triggerStepIdentifier in [_stepNavigationRules allKeys]) {
|
|
XCTAssertEqualObjects(_stepNavigationRules[triggerStepIdentifier], [_navigableOrderedTask navigationRuleForTriggerStepIdentifier:triggerStepIdentifier]);
|
|
}
|
|
|
|
ORKDefineStringKey(MockTriggerStepIdentifier);
|
|
ORKDefineStringKey(MockDestinationStepIdentifier);
|
|
|
|
// Test adding and removing a step navigation rule
|
|
XCTAssertNil([_navigableOrderedTask navigationRuleForTriggerStepIdentifier:MockTriggerStepIdentifier]);
|
|
|
|
ORKDirectStepNavigationRule *mockNavigationRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:MockDestinationStepIdentifier];
|
|
[_navigableOrderedTask setNavigationRule:mockNavigationRule forTriggerStepIdentifier:MockTriggerStepIdentifier];
|
|
|
|
XCTAssertEqualObjects([_navigableOrderedTask navigationRuleForTriggerStepIdentifier:MockTriggerStepIdentifier], [mockNavigationRule copy]);
|
|
|
|
ORKPredicateSkipStepNavigationRule *mockSkipNavigationRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:[NSPredicate predicateWithFormat:@"1 == 1"]];
|
|
[_navigableOrderedTask setSkipNavigationRule:mockSkipNavigationRule forStepIdentifier:MockTriggerStepIdentifier];
|
|
|
|
XCTAssertEqualObjects([_navigableOrderedTask skipNavigationRuleForStepIdentifier:MockTriggerStepIdentifier], [mockSkipNavigationRule copy]);
|
|
|
|
[_navigableOrderedTask removeSkipNavigationRuleForStepIdentifier:MockTriggerStepIdentifier];
|
|
XCTAssertNil([_navigableOrderedTask skipNavigationRuleForStepIdentifier:MockTriggerStepIdentifier]);
|
|
}
|
|
|
|
- (void)testNavigableOrderedTaskEmpty {
|
|
getIndividualNavigableOrderedTaskSteps();
|
|
|
|
//
|
|
// Empty task result
|
|
//
|
|
ORKTaskResult *taskResult = [self getResultTreeWithTaskIdentifier:NavigableOrderedTaskIdentifier resultOptions:0];
|
|
|
|
// Test forward navigation
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, symptomStep, otherSymptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, otherSymptomStep, endStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, endStep, nil));
|
|
|
|
// Test absent backward navigation
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, endStep, nil));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, otherSymptomStep, nil));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, symptomStep, nil));
|
|
|
|
// Test unreachable nodes
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severityStep, otherSymptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, blankStep, severeHeadacheStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severeHeadacheStep, endStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, severeHeadacheStep, nil));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, lightHeadacheStep, endStep));
|
|
|
|
}
|
|
|
|
- (void)testNavigableOrderedTaskHeadache {
|
|
getIndividualNavigableOrderedTaskSteps();
|
|
|
|
//
|
|
// Only headache symptom question step answered
|
|
//
|
|
ORKTaskResult *taskResult = [self getResultTreeWithTaskIdentifier:NavigableOrderedTaskIdentifier resultOptions:TestsTaskResultOptionSymptomHeadache | TestsTaskResultOptionSeverityYes];
|
|
|
|
// Test forward navigation
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, symptomStep, severityStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severityStep, severeHeadacheStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severeHeadacheStep, endStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, endStep, nil));
|
|
|
|
// Test backward navigation
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, endStep, severeHeadacheStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, severeHeadacheStep, severityStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, severityStep, symptomStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, symptomStep, nil));
|
|
}
|
|
|
|
- (void)testNavigableOrderedTaskDizziness {
|
|
getIndividualNavigableOrderedTaskSteps();
|
|
|
|
//
|
|
// Only dizziness symptom question answered
|
|
//
|
|
ORKTaskResult *taskResult = [self getResultTreeWithTaskIdentifier:NavigableOrderedTaskIdentifier resultOptions:TestsTaskResultOptionSymptomDizziness];
|
|
|
|
// Test forward navigation
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, symptomStep, otherSymptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, otherSymptomStep, endStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, endStep, nil));
|
|
|
|
// Test backward navigation
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, endStep, otherSymptomStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, otherSymptomStep, symptomStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, symptomStep, nil));
|
|
}
|
|
|
|
- (void)testNavigableOrderedTaskSevereHeadache {
|
|
getIndividualNavigableOrderedTaskSteps();
|
|
|
|
//
|
|
// Severe headache sequence
|
|
//
|
|
ORKTaskResult *taskResult = [self getResultTreeWithTaskIdentifier:NavigableOrderedTaskIdentifier resultOptions:TestsTaskResultOptionSymptomHeadache | TestsTaskResultOptionSeverityYes];
|
|
|
|
// Test forward navigation
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, symptomStep, severityStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severityStep, severeHeadacheStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severeHeadacheStep, endStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, endStep, nil));
|
|
|
|
// Test backward navigation
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, endStep, severeHeadacheStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, severeHeadacheStep, severityStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, severityStep, symptomStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, symptomStep, nil));
|
|
}
|
|
|
|
- (void)testNavigableOrderedTaskLightHeadache {
|
|
getIndividualNavigableOrderedTaskSteps();
|
|
|
|
//
|
|
// Light headache sequence
|
|
//
|
|
ORKTaskResult *taskResult = [self getResultTreeWithTaskIdentifier:NavigableOrderedTaskIdentifier resultOptions:TestsTaskResultOptionSymptomHeadache | TestsTaskResultOptionSeverityNo];
|
|
|
|
// Test forward navigation
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, symptomStep, severityStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, severityStep, lightHeadacheStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, lightHeadacheStep, endStep));
|
|
XCTAssertTrue(testStepAfterStep(_navigableOrderedTask, taskResult, endStep, nil));
|
|
|
|
// Test backward navigation
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, endStep, lightHeadacheStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, lightHeadacheStep, severityStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, severityStep, symptomStep));
|
|
XCTAssertTrue(testStepBeforeStep(_navigableOrderedTask, taskResult, symptomStep, nil));
|
|
}
|
|
|
|
- (void)testNavigableOrderedTaskSkip {
|
|
ORKNavigableOrderedTask *skipTask = [_navigableOrderedTask copy];
|
|
|
|
getIndividualNavigableOrderedTaskSteps();
|
|
|
|
//
|
|
// Light headache sequence
|
|
//
|
|
ORKTaskResult *taskResult = [self getResultTreeWithTaskIdentifier:NavigableOrderedTaskIdentifier resultOptions:TestsTaskResultOptionSymptomHeadache | TestsTaskResultOptionSeverityNo];
|
|
|
|
// User chose headache at the symptom step
|
|
ORKResultSelector *resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:SymptomStepIdentifier];
|
|
NSPredicate *predicateHeadache = [ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValue:HeadacheChoiceValue];
|
|
ORKPredicateSkipStepNavigationRule *skipRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicateHeadache];
|
|
|
|
// Skip endStep
|
|
[skipTask setSkipNavigationRule:skipRule forStepIdentifier:EndStepIdentifier];
|
|
|
|
// Test forward navigation
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, symptomStep, severityStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, severityStep, lightHeadacheStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, lightHeadacheStep, nil));
|
|
|
|
|
|
// Skip lightHeadacheStep
|
|
[skipTask removeSkipNavigationRuleForStepIdentifier:EndStepIdentifier];
|
|
[skipTask setSkipNavigationRule:skipRule forStepIdentifier:LightHeadacheStepIdentifier];
|
|
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, symptomStep, severityStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, severityStep, endStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, endStep, nil));
|
|
|
|
|
|
// Skip lightHeadache and endStep
|
|
[skipTask setSkipNavigationRule:skipRule forStepIdentifier:EndStepIdentifier];
|
|
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, nil, symptomStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, symptomStep, severityStep));
|
|
XCTAssertTrue(testStepAfterStep(skipTask, taskResult, severityStep, nil));
|
|
}
|
|
|
|
ORKDefineStringKey(SignConsentStepIdentifier);
|
|
ORKDefineStringKey(SignatureIdentifier);
|
|
|
|
ORKDefineStringKey(ScaleStepIdentifier);
|
|
ORKDefineStringKey(ContinuousScaleStepIdentifier);
|
|
static const NSInteger IntegerValue = 6;
|
|
static const float FloatValue = 6.5;
|
|
|
|
ORKDefineStringKey(SingleChoiceStepIdentifier);
|
|
ORKDefineStringKey(MultipleChoiceStepIdentifier);
|
|
ORKDefineStringKey(MixedMultipleChoiceStepIdentifier);
|
|
ORKDefineStringKey(SingleChoiceValue);
|
|
ORKDefineStringKey(MultipleChoiceValue1);
|
|
ORKDefineStringKey(MultipleChoiceValue2);
|
|
static const NSInteger MultipleChoiceValue3 = 7;
|
|
|
|
ORKDefineStringKey(BooleanStepIdentifier);
|
|
static const BOOL BooleanValue = YES;
|
|
|
|
ORKDefineStringKey(TextStepIdentifier);
|
|
ORKDefineStringKey(TextValue);
|
|
ORKDefineStringKey(OtherTextValue);
|
|
|
|
ORKDefineStringKey(IntegerNumericStepIdentifier);
|
|
ORKDefineStringKey(FloatNumericStepIdentifier);
|
|
|
|
ORKDefineStringKey(TimeOfDayStepIdentifier);
|
|
ORKDefineStringKey(TimeIntervalStepIdentifier);
|
|
ORKDefineStringKey(DateStepIdentifier);
|
|
|
|
ORKDefineStringKey(FormStepIdentifier);
|
|
|
|
ORKDefineStringKey(TextFormItemIdentifier);
|
|
ORKDefineStringKey(NumericFormItemIdentifier);
|
|
|
|
ORKDefineStringKey(NilTextStepIdentifier);
|
|
|
|
ORKDefineStringKey(AdditionalTaskIdentifier);
|
|
ORKDefineStringKey(AdditionalFormStepIdentifier);
|
|
ORKDefineStringKey(AdditionalTextFormItemIdentifier);
|
|
ORKDefineStringKey(AdditionalNumericFormItemIdentifier);
|
|
|
|
ORKDefineStringKey(AdditionalTextStepIdentifier);
|
|
ORKDefineStringKey(AdditionalTextValue);
|
|
|
|
ORKDefineStringKey(MatchedDestinationStepIdentifier);
|
|
ORKDefineStringKey(DefaultDestinationStepIdentifier);
|
|
|
|
static const NSInteger AdditionalIntegerValue = 42;
|
|
|
|
static NSDate *(^Date)(void) = ^NSDate *{ return [NSDate dateWithTimeIntervalSince1970:60*60*24]; };
|
|
static NSDateComponents *(^DateComponents)(void) = ^NSDateComponents *{
|
|
NSDateComponents *dateComponents = [NSDateComponents new];
|
|
dateComponents.hour = 6;
|
|
dateComponents.minute = 6;
|
|
return dateComponents;
|
|
};
|
|
|
|
static ORKQuestionResult *(^getQuestionResult)(NSString *, Class, ORKQuestionType, id) = ^ORKQuestionResult *(NSString *questionResultIdentifier, Class questionResultClass, ORKQuestionType questionType, id answer) {
|
|
ORKQuestionResult *questionResult = [[questionResultClass alloc] init];
|
|
questionResult.identifier = questionResultIdentifier;
|
|
questionResult.answer = answer;
|
|
questionResult.questionType = questionType;
|
|
return questionResult;
|
|
};
|
|
|
|
static ORKStepResult *(^getStepResult)(NSString *, Class, ORKQuestionType, id) = ^ORKStepResult *(NSString *stepIdentifier, Class questionResultClass, ORKQuestionType questionType, id answer) {
|
|
ORKQuestionResult *questionResult = getQuestionResult(stepIdentifier, questionResultClass, questionType, answer);
|
|
ORKStepResult *stepResult = [[ORKStepResult alloc] initWithStepIdentifier:stepIdentifier results:@[questionResult]];
|
|
return stepResult;
|
|
};
|
|
|
|
static ORKStepResult *(^getConsentStepResult)(NSString *, NSString *, BOOL) = ^ORKStepResult *(NSString *stepIdentifier, NSString *signatureIdentifier, BOOL consented) {
|
|
ORKConsentSignatureResult *consentSignatureResult = [[ORKConsentSignatureResult alloc] initWithIdentifier:signatureIdentifier];
|
|
consentSignatureResult.consented = consented;
|
|
return [[ORKStepResult alloc] initWithStepIdentifier:stepIdentifier results:@[consentSignatureResult]];
|
|
};
|
|
|
|
- (ORKTaskResult *)getGeneralTaskResultTree {
|
|
NSMutableArray *stepResults = [NSMutableArray new];
|
|
|
|
[stepResults addObject:getStepResult(ScaleStepIdentifier, [ORKScaleQuestionResult class], ORKQuestionTypeScale, @(IntegerValue))];
|
|
[stepResults addObject:getStepResult(ContinuousScaleStepIdentifier, [ORKScaleQuestionResult class], ORKQuestionTypeScale, @(FloatValue))];
|
|
|
|
[stepResults addObject:getStepResult(SingleChoiceStepIdentifier, [ORKChoiceQuestionResult class], ORKQuestionTypeSingleChoice, @[SingleChoiceValue])];
|
|
[stepResults addObject:getStepResult(MultipleChoiceStepIdentifier, [ORKChoiceQuestionResult class], ORKQuestionTypeMultipleChoice, @[MultipleChoiceValue1, MultipleChoiceValue2])];
|
|
[stepResults addObject:getStepResult(MixedMultipleChoiceStepIdentifier, [ORKChoiceQuestionResult class], ORKQuestionTypeMultipleChoice, @[MultipleChoiceValue1, MultipleChoiceValue2, @(MultipleChoiceValue3)])];
|
|
|
|
[stepResults addObject:getStepResult(BooleanStepIdentifier, [ORKBooleanQuestionResult class], ORKQuestionTypeBoolean, @(BooleanValue))];
|
|
|
|
[stepResults addObject:getStepResult(TextStepIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, TextValue)];
|
|
|
|
[stepResults addObject:getStepResult(IntegerNumericStepIdentifier, [ORKNumericQuestionResult class], ORKQuestionTypeInteger, @(IntegerValue))];
|
|
[stepResults addObject:getStepResult(FloatNumericStepIdentifier, [ORKNumericQuestionResult class], ORKQuestionTypeDecimal, @(FloatValue))];
|
|
|
|
[stepResults addObject:getStepResult(DateStepIdentifier, [ORKDateQuestionResult class], ORKQuestionTypeDate, Date())];
|
|
|
|
[stepResults addObject:getStepResult(TimeIntervalStepIdentifier, [ORKTimeIntervalQuestionResult class], ORKQuestionTypeTimeInterval, @(IntegerValue))];
|
|
|
|
[stepResults addObject:getStepResult(TimeOfDayStepIdentifier, [ORKTimeOfDayQuestionResult class], ORKQuestionTypeTimeOfDay, DateComponents())];
|
|
|
|
// Nil result (simulate skipped step)
|
|
[stepResults addObject:getStepResult(NilTextStepIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, nil)];
|
|
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:OrderedTaskIdentifier
|
|
taskRunUUID:[NSUUID UUID]
|
|
outputDirectory:[NSURL fileURLWithPath:NSTemporaryDirectory()]];
|
|
taskResult.results = stepResults;
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
- (ORKTaskResult *)getTaskResultTreeWithConsent:(BOOL)consented {
|
|
NSMutableArray *stepResults = [NSMutableArray new];
|
|
|
|
[stepResults addObject:getConsentStepResult(SignConsentStepIdentifier, SignatureIdentifier, consented)];
|
|
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:OrderedTaskIdentifier
|
|
taskRunUUID:[NSUUID UUID]
|
|
outputDirectory:[NSURL fileURLWithPath:NSTemporaryDirectory()]];
|
|
taskResult.results = stepResults;
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
- (ORKTaskResult *)getSmallTaskResultTreeWithIsAdditionalTask:(BOOL)isAdditionalTask {
|
|
NSMutableArray *stepResults = [NSMutableArray new];
|
|
|
|
if (!isAdditionalTask) {
|
|
[stepResults addObject:getStepResult(TextStepIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, TextValue)];
|
|
} else {
|
|
[stepResults addObject:getStepResult(AdditionalTextStepIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, AdditionalTextValue)];
|
|
}
|
|
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:!isAdditionalTask ? OrderedTaskIdentifier : AdditionalTaskIdentifier
|
|
taskRunUUID:[NSUUID UUID]
|
|
outputDirectory:[NSURL fileURLWithPath:NSTemporaryDirectory()]];
|
|
taskResult.results = stepResults;
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
- (ORKTaskResult *)getSmallFormTaskResultTreeWithIsAdditionalTask:(BOOL)isAdditionalTask {
|
|
NSMutableArray *formItemResults = [NSMutableArray new];
|
|
|
|
if (!isAdditionalTask) {
|
|
[formItemResults addObject:getQuestionResult(TextFormItemIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, TextValue)];
|
|
[formItemResults addObject:getQuestionResult(NumericFormItemIdentifier, [ORKNumericQuestionResult class], ORKQuestionTypeInteger, @(IntegerValue))];
|
|
} else {
|
|
[formItemResults addObject:getQuestionResult(AdditionalTextFormItemIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, AdditionalTextValue)];
|
|
[formItemResults addObject:getQuestionResult(AdditionalNumericFormItemIdentifier, [ORKNumericQuestionResult class], ORKQuestionTypeInteger, @(AdditionalIntegerValue))];
|
|
}
|
|
|
|
ORKStepResult *formStepResult = [[ORKStepResult alloc] initWithStepIdentifier:(!isAdditionalTask ? FormStepIdentifier : AdditionalFormStepIdentifier) results:formItemResults];
|
|
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:(!isAdditionalTask ? OrderedTaskIdentifier : AdditionalTaskIdentifier)
|
|
taskRunUUID:[NSUUID UUID]
|
|
outputDirectory:[NSURL fileURLWithPath:NSTemporaryDirectory()]];
|
|
taskResult.results = @[formStepResult];
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
- (ORKTaskResult *)getSmallTaskResultTreeWithDuplicateStepIdentifiers {
|
|
NSMutableArray *stepResults = [NSMutableArray new];
|
|
|
|
[stepResults addObject:getStepResult(TextStepIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, TextValue)];
|
|
[stepResults addObject:getStepResult(TextStepIdentifier, [ORKTextQuestionResult class], ORKQuestionTypeText, TextValue)];
|
|
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:OrderedTaskIdentifier
|
|
taskRunUUID:[NSUUID UUID]
|
|
outputDirectory:[NSURL fileURLWithPath:NSTemporaryDirectory()]];
|
|
taskResult.results = stepResults;
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
- (void)testPredicateStepNavigationRule {
|
|
NSPredicate *predicate = nil;
|
|
NSPredicate *predicateA = nil;
|
|
NSPredicate *predicateB = nil;
|
|
ORKPredicateStepNavigationRule *predicateRule = nil;
|
|
ORKTaskResult *taskResult = nil;
|
|
ORKTaskResult *additionalTaskResult = nil;
|
|
|
|
NSArray *resultPredicates = nil;
|
|
NSArray *destinationStepIdentifiers = nil;
|
|
NSString *defaultStepIdentifier = nil;
|
|
|
|
ORKResultSelector *resultSelector = nil;
|
|
|
|
{
|
|
// Test predicate step navigation rule initializers
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
resultPredicates = @[ predicate ];
|
|
destinationStepIdentifiers = @[ MatchedDestinationStepIdentifier ];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:resultPredicates
|
|
destinationStepIdentifiers:destinationStepIdentifiers];
|
|
|
|
XCTAssertEqualObjects(predicateRule.resultPredicates, ORKArrayCopyObjects(resultPredicates));
|
|
XCTAssertEqualObjects(predicateRule.destinationStepIdentifiers, ORKArrayCopyObjects(destinationStepIdentifiers));
|
|
XCTAssertNil(predicateRule.defaultStepIdentifier);
|
|
|
|
defaultStepIdentifier = DefaultDestinationStepIdentifier;
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:resultPredicates
|
|
destinationStepIdentifiers:destinationStepIdentifiers
|
|
defaultStepIdentifier:defaultStepIdentifier];
|
|
|
|
XCTAssertEqualObjects(predicateRule.resultPredicates, ORKArrayCopyObjects(resultPredicates));
|
|
XCTAssertEqualObjects(predicateRule.destinationStepIdentifiers, ORKArrayCopyObjects(destinationStepIdentifiers));
|
|
XCTAssertEqualObjects(predicateRule.defaultStepIdentifier, defaultStepIdentifier);
|
|
}
|
|
|
|
{
|
|
// Predicate matching, no additional task results, matching
|
|
taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:@"foo"
|
|
taskRunUUID:[NSUUID new]
|
|
outputDirectory:nil];
|
|
taskResult.identifier = OrderedTaskIdentifier;
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[ predicate ]
|
|
destinationStepIdentifiers:@[ MatchedDestinationStepIdentifier ]
|
|
defaultStepIdentifier:DefaultDestinationStepIdentifier];
|
|
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], DefaultDestinationStepIdentifier);
|
|
|
|
taskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], MatchedDestinationStepIdentifier);
|
|
}
|
|
|
|
{
|
|
// Predicate matching, no additional task results, non matching
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:OtherTextValue];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[ predicate ]
|
|
destinationStepIdentifiers:@[ MatchedDestinationStepIdentifier ]
|
|
defaultStepIdentifier:DefaultDestinationStepIdentifier];
|
|
taskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], DefaultDestinationStepIdentifier);
|
|
}
|
|
|
|
{
|
|
NSPredicate *currentPredicate = nil;
|
|
NSPredicate *additionalPredicate = nil;
|
|
|
|
// Predicate matching, additional task results
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
currentPredicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:AdditionalTaskIdentifier
|
|
resultIdentifier:AdditionalTextStepIdentifier];
|
|
additionalPredicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:AdditionalTextValue];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[currentPredicate, additionalPredicate]];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[ predicate ]
|
|
destinationStepIdentifiers:@[ MatchedDestinationStepIdentifier ]
|
|
defaultStepIdentifier:DefaultDestinationStepIdentifier];
|
|
|
|
taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:@"foo"
|
|
taskRunUUID:[NSUUID new]
|
|
outputDirectory:nil];
|
|
taskResult.identifier = OrderedTaskIdentifier;
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], DefaultDestinationStepIdentifier);
|
|
|
|
taskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], DefaultDestinationStepIdentifier);
|
|
|
|
additionalTaskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:YES];
|
|
predicateRule.additionalTaskResults = @[ additionalTaskResult ];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], MatchedDestinationStepIdentifier);
|
|
}
|
|
|
|
{
|
|
// Test duplicate task identifiers check
|
|
predicateRule.additionalTaskResults = @[ taskResult ];
|
|
XCTAssertThrows([predicateRule identifierForDestinationStepWithTaskResult:taskResult]);
|
|
|
|
// Test duplicate question result identifiers check
|
|
XCTAssertThrows(predicateRule.additionalTaskResults = @[ [self getSmallTaskResultTreeWithDuplicateStepIdentifiers] ]);
|
|
}
|
|
|
|
{
|
|
// Form predicate matching, no additional task results, matching
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:TextFormItemIdentifier];
|
|
predicateA = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:NumericFormItemIdentifier];
|
|
predicateB = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateA, predicateB]];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[ predicate ]
|
|
destinationStepIdentifiers:@[ MatchedDestinationStepIdentifier ]
|
|
defaultStepIdentifier:DefaultDestinationStepIdentifier];
|
|
|
|
taskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], MatchedDestinationStepIdentifier);
|
|
}
|
|
|
|
{
|
|
// Form predicate matching, no additional task results, non matching
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:TextFormItemIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:OtherTextValue];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[ predicate ]
|
|
destinationStepIdentifiers:@[ MatchedDestinationStepIdentifier ]
|
|
defaultStepIdentifier:DefaultDestinationStepIdentifier];
|
|
taskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], DefaultDestinationStepIdentifier);
|
|
}
|
|
|
|
{
|
|
NSPredicate *currentPredicate = nil;
|
|
NSPredicate *additionalPredicate = nil;
|
|
|
|
// Form predicate matching, additional task results
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:TextFormItemIdentifier];
|
|
predicateA = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:NumericFormItemIdentifier];
|
|
predicateB = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue];
|
|
|
|
currentPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateA, predicateB]];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:AdditionalTaskIdentifier
|
|
stepIdentifier:AdditionalFormStepIdentifier
|
|
resultIdentifier:AdditionalTextFormItemIdentifier];
|
|
predicateA = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:AdditionalTextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:AdditionalTaskIdentifier
|
|
stepIdentifier:AdditionalFormStepIdentifier
|
|
resultIdentifier:AdditionalNumericFormItemIdentifier];
|
|
predicateB = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:AdditionalIntegerValue];
|
|
|
|
additionalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateA, predicateB]];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[currentPredicate, additionalPredicate]];
|
|
predicateRule = [[ORKPredicateStepNavigationRule alloc] initWithResultPredicates:@[ predicate ]
|
|
destinationStepIdentifiers:@[ MatchedDestinationStepIdentifier ]
|
|
defaultStepIdentifier:DefaultDestinationStepIdentifier];
|
|
|
|
taskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], DefaultDestinationStepIdentifier);
|
|
|
|
additionalTaskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:YES];
|
|
predicateRule.additionalTaskResults = @[ additionalTaskResult ];
|
|
XCTAssertEqualObjects([predicateRule identifierForDestinationStepWithTaskResult:taskResult], MatchedDestinationStepIdentifier);
|
|
}
|
|
}
|
|
|
|
- (void)testPredicateSkipStepNavigationRule {
|
|
NSPredicate *predicate = nil;
|
|
NSPredicate *predicateA = nil;
|
|
NSPredicate *predicateB = nil;
|
|
ORKPredicateSkipStepNavigationRule *predicateRule = nil;
|
|
ORKTaskResult *taskResult = nil;
|
|
ORKTaskResult *additionalTaskResult = nil;
|
|
|
|
ORKResultSelector *resultSelector = nil;
|
|
|
|
{
|
|
// Test predicate step navigation rule initializers
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
XCTAssertEqualObjects(predicateRule.resultPredicate, predicate);
|
|
}
|
|
|
|
{
|
|
// Predicate matching, no additional task results, matching
|
|
taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:@"foo"
|
|
taskRunUUID:[NSUUID new]
|
|
outputDirectory:nil];
|
|
taskResult.identifier = OrderedTaskIdentifier;
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
|
|
XCTAssertFalse([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
|
|
taskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertTrue([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
}
|
|
|
|
{
|
|
// Predicate matching, no additional task results, non matching
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:OtherTextValue];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
taskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertFalse([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
}
|
|
|
|
{
|
|
NSPredicate *currentPredicate = nil;
|
|
NSPredicate *additionalPredicate = nil;
|
|
|
|
// Predicate matching, additional task results
|
|
resultSelector = [[ORKResultSelector alloc] initWithResultIdentifier:TextStepIdentifier];
|
|
currentPredicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:AdditionalTaskIdentifier
|
|
resultIdentifier:AdditionalTextStepIdentifier];
|
|
additionalPredicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:AdditionalTextValue];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[currentPredicate, additionalPredicate]];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
|
|
taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:@"foo"
|
|
taskRunUUID:[NSUUID new]
|
|
outputDirectory:nil];
|
|
taskResult.identifier = OrderedTaskIdentifier;
|
|
XCTAssertFalse([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
|
|
taskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertFalse([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
|
|
additionalTaskResult = [self getSmallTaskResultTreeWithIsAdditionalTask:YES];
|
|
predicateRule.additionalTaskResults = @[ additionalTaskResult ];
|
|
XCTAssertTrue([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
}
|
|
|
|
{
|
|
// Test duplicate task identifiers check
|
|
predicateRule.additionalTaskResults = @[ taskResult ];
|
|
XCTAssertThrows([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
|
|
// Test duplicate question result identifiers check
|
|
XCTAssertThrows(predicateRule.additionalTaskResults = @[ [self getSmallTaskResultTreeWithDuplicateStepIdentifiers] ]);
|
|
}
|
|
|
|
{
|
|
// Form predicate matching, no additional task results, matching
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:TextFormItemIdentifier];
|
|
predicateA = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:NumericFormItemIdentifier];
|
|
predicateB = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateA, predicateB]];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
|
|
taskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertTrue([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
}
|
|
|
|
{
|
|
// Form predicate matching, no additional task results, non matching
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:TextFormItemIdentifier];
|
|
predicate = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:OtherTextValue];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
|
|
taskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertFalse([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
}
|
|
|
|
{
|
|
NSPredicate *currentPredicate = nil;
|
|
NSPredicate *additionalPredicate = nil;
|
|
|
|
// Form predicate matching, additional task results
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:TextFormItemIdentifier];
|
|
predicateA = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithStepIdentifier:FormStepIdentifier
|
|
resultIdentifier:NumericFormItemIdentifier];
|
|
predicateB = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue];
|
|
|
|
currentPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateA, predicateB]];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:AdditionalTaskIdentifier
|
|
stepIdentifier:AdditionalFormStepIdentifier
|
|
resultIdentifier:AdditionalTextFormItemIdentifier];
|
|
predicateA = [ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:AdditionalTextValue];
|
|
|
|
resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:AdditionalTaskIdentifier
|
|
stepIdentifier:AdditionalFormStepIdentifier
|
|
resultIdentifier:AdditionalNumericFormItemIdentifier];
|
|
predicateB = [ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:AdditionalIntegerValue];
|
|
|
|
additionalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicateA, predicateB]];
|
|
|
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[currentPredicate, additionalPredicate]];
|
|
predicateRule = [[ORKPredicateSkipStepNavigationRule alloc] initWithResultPredicate:predicate];
|
|
|
|
taskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:NO];
|
|
XCTAssertFalse([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
|
|
additionalTaskResult = [self getSmallFormTaskResultTreeWithIsAdditionalTask:YES];
|
|
predicateRule.additionalTaskResults = @[ additionalTaskResult ];
|
|
XCTAssertTrue([predicateRule stepShouldSkipWithTaskResult:taskResult]);
|
|
}
|
|
}
|
|
|
|
- (void)testDirectStepNavigationRule {
|
|
ORKDirectStepNavigationRule *directRule = nil;
|
|
ORKTaskResult *mockTaskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:@"foo"
|
|
taskRunUUID:[NSUUID new]
|
|
outputDirectory:nil];
|
|
|
|
directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:MatchedDestinationStepIdentifier];
|
|
XCTAssertEqualObjects(directRule.destinationStepIdentifier, [MatchedDestinationStepIdentifier copy] );
|
|
XCTAssertEqualObjects([directRule identifierForDestinationStepWithTaskResult:mockTaskResult], [MatchedDestinationStepIdentifier copy]);
|
|
|
|
directRule = [[ORKDirectStepNavigationRule alloc] initWithDestinationStepIdentifier:ORKNullStepIdentifier];
|
|
XCTAssertEqualObjects(directRule.destinationStepIdentifier, [ORKNullStepIdentifier copy]);
|
|
XCTAssertEqualObjects([directRule identifierForDestinationStepWithTaskResult:mockTaskResult], [ORKNullStepIdentifier copy]);
|
|
}
|
|
|
|
- (void)testResultPredicatesWithTaskIdentifier:(NSString *)taskIdentifier
|
|
substitutionVariables:(NSDictionary *)substitutionVariables
|
|
taskResults:(NSArray *)taskResults {
|
|
// ORKScaleQuestionResult
|
|
ORKResultSelector *resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:taskIdentifier
|
|
resultIdentifier:@""];
|
|
|
|
resultSelector.resultIdentifier = ScaleStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue + 1] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
resultSelector.resultIdentifier = ContinuousScaleStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.05
|
|
maximumExpectedAnswerValue:FloatValue + 0.06] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForScaleQuestionResultWithResultSelector:resultSelector
|
|
maximumExpectedAnswerValue:FloatValue - 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKChoiceQuestionResult (strings)
|
|
resultSelector.resultIdentifier = SingleChoiceStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValue:SingleChoiceValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValue:OtherTextValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
resultSelector.resultIdentifier = MultipleChoiceStepIdentifier;
|
|
NSArray *expectedAnswers = nil;
|
|
expectedAnswers = @[MultipleChoiceValue1];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[MultipleChoiceValue1, MultipleChoiceValue2];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[MultipleChoiceValue1, MultipleChoiceValue2, OtherTextValue];
|
|
XCTAssertFalse([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[MultipleChoiceValue1, MultipleChoiceValue2, @(MultipleChoiceValue3)];
|
|
XCTAssertFalse([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
resultSelector.resultIdentifier = MixedMultipleChoiceStepIdentifier;
|
|
expectedAnswers = @[MultipleChoiceValue1];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[@(MultipleChoiceValue3)];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[MultipleChoiceValue1, MultipleChoiceValue2, @(MultipleChoiceValue3)];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[MultipleChoiceValue1, MultipleChoiceValue2, OtherTextValue];
|
|
XCTAssertFalse([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValues:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKChoiceQuestionResult (regular expressions)
|
|
resultSelector.resultIdentifier = SingleChoiceStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
matchingPattern:@"...gleChoiceValue"] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswerValue:@"...SingleChoiceValue"] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
resultSelector.resultIdentifier = MultipleChoiceStepIdentifier;
|
|
expectedAnswers = @[@"...tipleChoiceValue1", @"...tipleChoiceValue2"];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
matchingPatterns:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedAnswers = @[@"...MultipleChoiceValue1", @"...MultipleChoiceValue2", @"...OtherTextValue"];
|
|
XCTAssertFalse([[ORKResultPredicate predicateForChoiceQuestionResultWithResultSelector:resultSelector
|
|
matchingPatterns:expectedAnswers] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKBooleanQuestionResult
|
|
resultSelector.resultIdentifier = BooleanStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForBooleanQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:BooleanValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForBooleanQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:!BooleanValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKTextQuestionResult (strings)
|
|
resultSelector.resultIdentifier = TextStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:TextValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
expectedString:OtherTextValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKTextQuestionResult (regular expressions)
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
matchingPattern:@"...tValue"] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTextQuestionResultWithResultSelector:resultSelector
|
|
matchingPattern:@"...TextValue"] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKNumericQuestionResult
|
|
resultSelector.resultIdentifier = IntegerNumericStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertFalse([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:IntegerValue + 1] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
resultSelector.resultIdentifier = FloatNumericStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:ORKIgnoreDoubleValue
|
|
maximumExpectedAnswerValue:ORKIgnoreDoubleValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.05
|
|
maximumExpectedAnswerValue:FloatValue + 0.06] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.05
|
|
maximumExpectedAnswerValue:FloatValue + 0.06] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForNumericQuestionResultWithResultSelector:resultSelector
|
|
maximumExpectedAnswerValue:FloatValue - 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKTimeOfDayQuestionResult
|
|
resultSelector.resultIdentifier = TimeOfDayStepIdentifier;
|
|
NSDateComponents *expectedDateComponentsMinimum = DateComponents();
|
|
NSDateComponents *expectedDateComponentsMaximum = DateComponents();
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeOfDayQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedHour:expectedDateComponentsMinimum.hour
|
|
minimumExpectedMinute:expectedDateComponentsMinimum.minute
|
|
maximumExpectedHour:expectedDateComponentsMaximum.hour
|
|
maximumExpectedMinute:expectedDateComponentsMaximum.minute] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
expectedDateComponentsMinimum.minute -= 2;
|
|
expectedDateComponentsMaximum.minute += 2;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeOfDayQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedHour:expectedDateComponentsMinimum.hour
|
|
minimumExpectedMinute:expectedDateComponentsMinimum.minute
|
|
maximumExpectedHour:expectedDateComponentsMaximum.hour
|
|
maximumExpectedMinute:expectedDateComponentsMaximum.minute] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
expectedDateComponentsMinimum.minute += 3;
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTimeOfDayQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedHour:expectedDateComponentsMinimum.hour
|
|
minimumExpectedMinute:expectedDateComponentsMinimum.minute
|
|
maximumExpectedHour:expectedDateComponentsMaximum.hour
|
|
maximumExpectedMinute:expectedDateComponentsMaximum.minute] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
expectedDateComponentsMinimum.minute -= 3;
|
|
expectedDateComponentsMinimum.hour += 1;
|
|
expectedDateComponentsMaximum.hour += 2;
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTimeOfDayQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedHour:expectedDateComponentsMinimum.hour
|
|
minimumExpectedMinute:expectedDateComponentsMinimum.minute
|
|
maximumExpectedHour:expectedDateComponentsMaximum.hour
|
|
maximumExpectedMinute:expectedDateComponentsMaximum.minute] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKTimeIntervalQuestionResult
|
|
resultSelector.resultIdentifier = FloatNumericStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:ORKIgnoreTimeIntervalValue
|
|
maximumExpectedAnswerValue:ORKIgnoreTimeIntervalValue] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.05
|
|
maximumExpectedAnswerValue:FloatValue + 0.06] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.05
|
|
maximumExpectedAnswerValue:FloatValue + 0.06] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue - 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
maximumExpectedAnswerValue:FloatValue + 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForTimeIntervalQuestionResultWithResultSelector:resultSelector
|
|
maximumExpectedAnswerValue:FloatValue - 0.01] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// ORKDateQuestionResult
|
|
resultSelector.resultIdentifier = DateStepIdentifier;
|
|
NSDate *expectedDate = Date();
|
|
XCTAssertTrue([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:-60]
|
|
maximumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:+60]] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:+60]
|
|
maximumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:+120]] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:-60]
|
|
maximumExpectedAnswerDate:nil] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:+1]
|
|
maximumExpectedAnswerDate:nil] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:nil
|
|
maximumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:+60]] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:nil
|
|
maximumExpectedAnswerDate:[expectedDate dateByAddingTimeInterval:-1]] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForDateQuestionResultWithResultSelector:resultSelector
|
|
minimumExpectedAnswerDate:nil
|
|
maximumExpectedAnswerDate:nil] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
// Result with nil value
|
|
resultSelector.resultIdentifier = NilTextStepIdentifier;
|
|
XCTAssertTrue([[ORKResultPredicate predicateForNilQuestionResultWithResultSelector:resultSelector] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
|
|
resultSelector.resultIdentifier = TextStepIdentifier;
|
|
XCTAssertFalse([[ORKResultPredicate predicateForNilQuestionResultWithResultSelector:resultSelector] evaluateWithObject:taskResults substitutionVariables:substitutionVariables]);
|
|
}
|
|
|
|
- (void)testConsentPredicate {
|
|
ORKResultSelector *resultSelector = [[ORKResultSelector alloc] initWithTaskIdentifier:OrderedTaskIdentifier
|
|
stepIdentifier:SignConsentStepIdentifier
|
|
resultIdentifier:SignatureIdentifier];
|
|
{
|
|
ORKTaskResult *consentedTaskResult = [self getTaskResultTreeWithConsent:YES];
|
|
XCTAssertTrue([[ORKResultPredicate predicateForConsentWithResultSelector:resultSelector
|
|
didConsent:YES] evaluateWithObject:@[consentedTaskResult] substitutionVariables:nil]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForConsentWithResultSelector:resultSelector
|
|
didConsent:NO] evaluateWithObject:@[consentedTaskResult] substitutionVariables:nil]);
|
|
}
|
|
|
|
{
|
|
ORKTaskResult *didNotConsentTaskResult = [self getTaskResultTreeWithConsent:NO];
|
|
|
|
XCTAssertTrue([[ORKResultPredicate predicateForConsentWithResultSelector:resultSelector
|
|
didConsent:NO] evaluateWithObject:@[didNotConsentTaskResult] substitutionVariables:nil]);
|
|
XCTAssertFalse([[ORKResultPredicate predicateForConsentWithResultSelector:resultSelector
|
|
didConsent:YES] evaluateWithObject:@[didNotConsentTaskResult] substitutionVariables:nil]);
|
|
}
|
|
}
|
|
|
|
- (void)testResultPredicates {
|
|
ORKTaskResult *taskResult = [self getGeneralTaskResultTree];
|
|
NSArray *taskResults = @[ taskResult ];
|
|
|
|
// The following two calls are equivalent since 'substitutionVariables' are ignored when you provide a non-nil task identifier
|
|
[self testResultPredicatesWithTaskIdentifier:OrderedTaskIdentifier
|
|
substitutionVariables:nil
|
|
taskResults:taskResults];
|
|
[self testResultPredicatesWithTaskIdentifier:OrderedTaskIdentifier
|
|
substitutionVariables:@{ORKResultPredicateTaskIdentifierVariableName: OrderedTaskIdentifier}
|
|
taskResults:taskResults];
|
|
// Test nil task identifier variable substitution
|
|
[self testResultPredicatesWithTaskIdentifier:nil
|
|
substitutionVariables:@{ORKResultPredicateTaskIdentifierVariableName: OrderedTaskIdentifier}
|
|
taskResults:taskResults];
|
|
}
|
|
|
|
- (void)testStepViewControllerWillDisappear {
|
|
TestTaskViewControllerDelegate *delegate = [[TestTaskViewControllerDelegate alloc] init];
|
|
ORKOrderedTask *task = [ORKOrderedTask twoFingerTappingIntervalTaskWithIdentifier:@"test" intendedUseDescription:nil duration:30 handOptions:0 options:0];
|
|
ORKTaskViewController *taskViewController = [[MockTaskViewController alloc] initWithTask:task taskRunUUID:nil];
|
|
taskViewController.delegate = delegate;
|
|
ORKInstructionStepViewController *stepViewController = [[ORKInstructionStepViewController alloc] initWithStep:task.steps.firstObject];
|
|
|
|
//-- call method under test
|
|
[taskViewController stepViewController:stepViewController didFinishWithNavigationDirection:ORKStepViewControllerNavigationDirectionForward];
|
|
|
|
// Check that the expected methods were called
|
|
XCTAssertEqual(delegate.methodCalled.count, 1);
|
|
XCTAssertEqualObjects(delegate.methodCalled.firstObject.selectorName, @"taskViewController:stepViewControllerWillDisappear:navigationDirection:");
|
|
NSArray *expectedArgs = @[taskViewController, stepViewController, @(ORKStepViewControllerNavigationDirectionForward)];
|
|
XCTAssertEqualObjects(delegate.methodCalled.firstObject.arguments, expectedArgs);
|
|
}
|
|
|
|
- (void)testTaskViewControllerCanDiscardLogic {
|
|
TestTaskViewControllerDelegate *delegate = [[TestTaskViewControllerDelegate alloc] init];
|
|
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:@"TestTask" steps:@[
|
|
[[ORKInstructionStep alloc] initWithIdentifier:@"instuction-0"],
|
|
[ORKReviewStep standaloneReviewStepWithIdentifier:@"review" steps:nil resultSource:nil],
|
|
]];
|
|
|
|
// test cases where hasSaveableResults == NO
|
|
{
|
|
MockTaskViewController *taskViewController = [[MockTaskViewController alloc] initWithTask:task taskRunUUID:nil];
|
|
taskViewController.delegate = delegate;
|
|
taskViewController.overrideHasSaveableResults = @(NO);
|
|
|
|
XCTAssertFalse(taskViewController.modalInPresentation, "modalInPresentation should default to NO");
|
|
[taskViewController viewWillAppear:false]; // get the first step loaded
|
|
XCTAssertFalse(taskViewController.modalInPresentation, "modalInPresentation should be NO after viewWillAppear if hasSaveableResults = NO and the current stepViewController is an instructionStep");
|
|
|
|
// if currentStep == instructionStep and not saveable -> canDiscardResults
|
|
XCTAssertEqual(taskViewController.currentStepViewController.step.identifier , @"instuction-0");
|
|
XCTAssertTrue([taskViewController isSafeToSkipConfirmation]);
|
|
}
|
|
|
|
// test cases where hasSaveableResults == YES
|
|
{
|
|
MockTaskViewController *taskViewController = [[MockTaskViewController alloc] initWithTask:task taskRunUUID:nil];
|
|
taskViewController.delegate = delegate;
|
|
taskViewController.overrideHasSaveableResults = @(YES);
|
|
|
|
XCTAssertFalse(taskViewController.modalInPresentation, "modalInPresentation should default to NO");
|
|
[taskViewController viewWillAppear:false]; // get the first step loaded
|
|
XCTAssertTrue(taskViewController.modalInPresentation, "modalInPresentation should be YES after viewWillAppear if hasSaveableResults = YES and the current stepViewController is an instructionStep");
|
|
|
|
// if currentStep == instructionStep and saveable -> CANNOT discardResults
|
|
XCTAssertEqual(taskViewController.currentStepViewController.step.identifier , @"instuction-0");
|
|
XCTAssertFalse([taskViewController isSafeToSkipConfirmation]);
|
|
}
|
|
|
|
{
|
|
// create a reviewStep with steps
|
|
ORKStep *reviewableStep = [ORKQuestionStep questionStepWithIdentifier:@"Who's there?" title:nil question:nil answer:nil];
|
|
ORKReviewStep *standaloneReviewStep = [ORKReviewStep standaloneReviewStepWithIdentifier:@"standalone-review" steps:@[reviewableStep] resultSource:nil];
|
|
[task addStep:standaloneReviewStep];
|
|
XCTAssertTrue(ORKDynamicCast([[task steps] lastObject], ORKReviewStep).isStandalone, "review step either was in the wrong spot in the task.steps array, or computed an unexpected value for `isStandalone`. reviewStep with steps != nil should return YES for isStandalone");
|
|
|
|
MockTaskViewController *taskViewController = [[MockTaskViewController alloc] initWithTask:task taskRunUUID:nil];
|
|
[taskViewController viewWillAppear:false]; // get the first step loaded
|
|
|
|
// step forward to the standalone reviewStep
|
|
[taskViewController goForward];
|
|
[taskViewController goForward];
|
|
ORKReviewStep *testStep = ORKDynamicCast(taskViewController.currentStepViewController.step, ORKReviewStep);
|
|
XCTAssertEqual([testStep identifier], @"standalone-review");
|
|
|
|
ORKReviewStepViewController *reviewViewController = ORKDynamicCast(taskViewController.currentStepViewController, ORKReviewStepViewController);
|
|
XCTAssertNotNil(reviewViewController, "taskViewController.currentStepViewController should be of type ORKReviewStepViewController at this point");
|
|
}
|
|
|
|
{
|
|
ORKStep *questionStep = [ORKQuestionStep questionStepWithIdentifier:@"Who's there?" title:nil question:nil answer:nil];
|
|
ORKOrderedTask *task = [[ORKOrderedTask alloc] initWithIdentifier:@"basic task" steps:@[
|
|
questionStep
|
|
]];
|
|
MockTaskViewController *taskViewController = [[MockTaskViewController alloc] initWithTask:task taskRunUUID:nil];
|
|
[taskViewController viewWillAppear:false]; // get the first step loaded
|
|
|
|
// confirm we have the expected currentStepViewController
|
|
XCTAssertEqual(taskViewController.currentStepViewController.step.identifier, @"Who's there?");
|
|
|
|
// if current viewController.readOnly is FALSE -> CANNOT discardResults
|
|
XCTAssertFalse([taskViewController isSafeToSkipConfirmation]);
|
|
}
|
|
|
|
}
|
|
|
|
- (void)testIndexOfStep {
|
|
ORKOrderedTask *task = [ORKOrderedTask twoFingerTappingIntervalTaskWithIdentifier:@"tapping" intendedUseDescription:nil duration:30 handOptions:0 options:0];
|
|
|
|
// get the first step
|
|
ORKStep *step0 = [task.steps firstObject];
|
|
XCTAssertNotNil(step0);
|
|
XCTAssertEqual([task indexOfStep:step0], 0);
|
|
|
|
// get the second step
|
|
ORKStep *step1 = [task stepWithIdentifier:ORKInstruction1StepIdentifier];
|
|
XCTAssertNotNil(step1);
|
|
XCTAssertEqual([task indexOfStep:step1], 1);
|
|
|
|
// get the last step
|
|
ORKStep *stepLast = [task.steps lastObject];
|
|
XCTAssertNotNil(stepLast);
|
|
XCTAssertEqual([task indexOfStep:stepLast], task.steps.count - 1);
|
|
|
|
// Look for not found
|
|
ORKStep *stepNF = [[ORKStep alloc] initWithIdentifier:@"foo"];
|
|
XCTAssertEqual([task indexOfStep:stepNF], NSNotFound);
|
|
|
|
}
|
|
|
|
- (void)testAudioTask_WithSoundCheck {
|
|
ORKNavigableOrderedTask *task = [ORKOrderedTask audioTaskWithIdentifier:@"audio" intendedUseDescription:nil speechInstruction:nil shortSpeechInstruction:nil duration:20 recordingSettings:nil checkAudioLevel:YES options:0];
|
|
|
|
NSArray *expectedStepIdentifiers = @[ORKInstruction0StepIdentifier,
|
|
ORKInstruction1StepIdentifier,
|
|
ORKCountdownStepIdentifier,
|
|
ORKAudioTooLoudStepIdentifier,
|
|
ORKAudioStepIdentifier,
|
|
ORKConclusionStepIdentifier];
|
|
NSArray *stepIdentifiers = [task.steps valueForKey:@"identifier"];
|
|
XCTAssertEqual(stepIdentifiers.count, expectedStepIdentifiers.count);
|
|
XCTAssertEqualObjects(stepIdentifiers, expectedStepIdentifiers);
|
|
|
|
XCTAssertNotNil([task navigationRuleForTriggerStepIdentifier:ORKCountdownStepIdentifier]);
|
|
XCTAssertNotNil([task navigationRuleForTriggerStepIdentifier:ORKAudioTooLoudStepIdentifier]);
|
|
}
|
|
|
|
- (void)testAudioTask_NoSoundCheck {
|
|
|
|
ORKNavigableOrderedTask *task = [ORKOrderedTask audioTaskWithIdentifier:@"audio" intendedUseDescription:nil speechInstruction:nil shortSpeechInstruction:nil duration:20 recordingSettings:nil checkAudioLevel:NO options:0];
|
|
|
|
NSArray *expectedStepIdentifiers = @[ORKInstruction0StepIdentifier,
|
|
ORKInstruction1StepIdentifier,
|
|
ORKCountdownStepIdentifier,
|
|
ORKAudioStepIdentifier,
|
|
ORKConclusionStepIdentifier];
|
|
NSArray *stepIdentifiers = [task.steps valueForKey:@"identifier"];
|
|
XCTAssertEqual(stepIdentifiers.count, expectedStepIdentifiers.count);
|
|
XCTAssertEqualObjects(stepIdentifiers, expectedStepIdentifiers);
|
|
XCTAssertEqual(task.stepNavigationRules.count, 0);
|
|
}
|
|
|
|
- (void)testWalkBackAndForthTask_30SecondDuration {
|
|
|
|
// Create the task
|
|
ORKOrderedTask *task = [ORKOrderedTask walkBackAndForthTaskWithIdentifier:@"walking" intendedUseDescription:nil walkDuration:30 restDuration:30 options:0];
|
|
|
|
// Check that the steps match the expected - If these change, it will affect the results and
|
|
// could adversely impact existing studies that are expecting this step order.
|
|
NSArray *expectedStepIdentifiers = @[ORKInstruction0StepIdentifier,
|
|
ORKInstruction1StepIdentifier,
|
|
ORKCountdownStepIdentifier,
|
|
ORKShortWalkOutboundStepIdentifier,
|
|
ORKShortWalkRestStepIdentifier,
|
|
ORKConclusionStepIdentifier];
|
|
XCTAssertEqual(task.steps.count, expectedStepIdentifiers.count);
|
|
NSArray *stepIdentifiers = [task.steps valueForKey:@"identifier"];
|
|
XCTAssertEqualObjects(stepIdentifiers, expectedStepIdentifiers);
|
|
|
|
// Check that the active steps include speaking the halfway point
|
|
ORKActiveStep *walkingStep = (ORKActiveStep *)[task stepWithIdentifier:ORKShortWalkOutboundStepIdentifier];
|
|
XCTAssertTrue(walkingStep.shouldSpeakRemainingTimeAtHalfway);
|
|
ORKActiveStep *restStep = (ORKActiveStep *)[task stepWithIdentifier:ORKShortWalkRestStepIdentifier];
|
|
XCTAssertTrue(restStep.shouldSpeakRemainingTimeAtHalfway);
|
|
|
|
}
|
|
|
|
- (void)testWalkBackAndForthTask_15SecondDuration_NoRest {
|
|
|
|
// Create the task
|
|
ORKOrderedTask *task = [ORKOrderedTask walkBackAndForthTaskWithIdentifier:@"walking" intendedUseDescription:nil walkDuration:15 restDuration:0 options:0];
|
|
|
|
// Check that the steps match the expected - If these change, it will affect the results and
|
|
// could adversely impact existing studies that are expecting this step order.
|
|
NSArray *expectedStepIdentifiers = @[ORKInstruction0StepIdentifier,
|
|
ORKInstruction1StepIdentifier,
|
|
ORKCountdownStepIdentifier,
|
|
ORKShortWalkOutboundStepIdentifier,
|
|
ORKConclusionStepIdentifier];
|
|
XCTAssertEqual(task.steps.count, expectedStepIdentifiers.count);
|
|
NSArray *stepIdentifiers = [task.steps valueForKey:@"identifier"];
|
|
XCTAssertEqualObjects(stepIdentifiers, expectedStepIdentifiers);
|
|
|
|
// Check that the active steps include speaking the halfway point
|
|
ORKActiveStep *walkingStep = (ORKActiveStep *)[task stepWithIdentifier:ORKShortWalkOutboundStepIdentifier];
|
|
XCTAssertFalse(walkingStep.shouldSpeakRemainingTimeAtHalfway);
|
|
|
|
}
|
|
|
|
#pragma mark - two-finger tapping with both hands
|
|
|
|
- (void)testTwoFingerTappingIntervalTaskWithIdentifier_TapHandOptionUndefined {
|
|
|
|
ORKOrderedTask *task = [ORKOrderedTask twoFingerTappingIntervalTaskWithIdentifier:@"test"
|
|
intendedUseDescription:nil
|
|
duration:10
|
|
handOptions:0
|
|
options:0];
|
|
NSArray *expectedStepIdentifiers = @[ORKInstruction0StepIdentifier,
|
|
ORKInstruction1StepIdentifier,
|
|
ORKTappingStepIdentifier,
|
|
ORKConclusionStepIdentifier];
|
|
NSArray *stepIdentifiers = [task.steps valueForKey:@"identifier"];
|
|
XCTAssertEqual(stepIdentifiers.count, expectedStepIdentifiers.count);
|
|
XCTAssertEqualObjects(stepIdentifiers, expectedStepIdentifiers);
|
|
|
|
ORKStep *tappingStep = [task stepWithIdentifier:ORKTappingStepIdentifier];
|
|
XCTAssertFalse(tappingStep.optional);
|
|
|
|
}
|
|
|
|
- (void)testTwoFingerTappingIntervalTaskWithIdentifier_TapHandOptionLeft {
|
|
|
|
ORKOrderedTask *task = [ORKOrderedTask twoFingerTappingIntervalTaskWithIdentifier:@"test"
|
|
intendedUseDescription:nil
|
|
duration:10
|
|
handOptions:ORKPredefinedTaskHandOptionLeft
|
|
options:0];
|
|
// Check assumption around how many steps
|
|
XCTAssertEqual(task.steps.count, 4);
|
|
|
|
// Check that none of the language or identifiers contain the word "right"
|
|
for (ORKStep *step in task.steps) {
|
|
XCTAssertFalse([step.identifier.lowercaseString hasSuffix:@"right"]);
|
|
XCTAssertFalse([step.title.lowercaseString containsString:@"right"]);
|
|
XCTAssertFalse([step.text.lowercaseString containsString:@"right"]);
|
|
}
|
|
|
|
NSArray * (^filteredSteps)(NSString*, NSString*) = ^(NSString *part1, NSString *part2) {
|
|
NSString *keyValue = [NSString stringWithFormat:@"%@.%@", part1, part2];
|
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", NSStringFromSelector(@selector(identifier)), keyValue];
|
|
return [task.steps filteredArrayUsingPredicate:predicate];
|
|
};
|
|
|
|
// Look for instruction step
|
|
NSArray *instructions = filteredSteps(@"instruction1", @"left");
|
|
XCTAssertEqual(instructions.count, 1);
|
|
ORKStep *instructionStep = [instructions firstObject];
|
|
XCTAssertEqualObjects(instructionStep.title, @"Left Hand");
|
|
XCTAssertEqualObjects(instructionStep.text, @"Put your device on a flat surface. Use two fingers on your left hand to alternately tap the buttons on the screen. Tap one finger, then the other. Try to time your taps to be as even as possible. Keep tapping for 10 seconds.");
|
|
|
|
// Look for the activity step
|
|
NSArray *tappings = filteredSteps(@"tapping", @"left");
|
|
XCTAssertEqual(tappings.count, 1);
|
|
ORKStep *tappingStep = [tappings firstObject];
|
|
XCTAssertEqualObjects(tappingStep.text, @"Tap the buttons using your LEFT hand.");
|
|
XCTAssertFalse(tappingStep.optional);
|
|
|
|
}
|
|
|
|
- (void)testTwoFingerTappingIntervalTaskWithIdentifier_TapHandOptionRight {
|
|
|
|
ORKOrderedTask *task = [ORKOrderedTask twoFingerTappingIntervalTaskWithIdentifier:@"test"
|
|
intendedUseDescription:nil
|
|
duration:10
|
|
handOptions:ORKPredefinedTaskHandOptionRight
|
|
options:0];
|
|
// Check assumption around how many steps
|
|
XCTAssertEqual(task.steps.count, 4);
|
|
|
|
// Check that none of the language or identifiers contain the word "right"
|
|
for (ORKStep *step in task.steps) {
|
|
XCTAssertFalse([step.identifier.lowercaseString hasSuffix:@"left"]);
|
|
XCTAssertFalse([step.title.lowercaseString containsString:@"left"]);
|
|
XCTAssertFalse([step.text.lowercaseString containsString:@"left"]);
|
|
}
|
|
|
|
NSArray * (^filteredSteps)(NSString*, NSString*) = ^(NSString *part1, NSString *part2) {
|
|
NSString *keyValue = [NSString stringWithFormat:@"%@.%@", part1, part2];
|
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", NSStringFromSelector(@selector(identifier)), keyValue];
|
|
return [task.steps filteredArrayUsingPredicate:predicate];
|
|
};
|
|
|
|
// Look for instruction step
|
|
NSArray *instructions = filteredSteps(@"instruction1", @"right");
|
|
XCTAssertEqual(instructions.count, 1);
|
|
ORKStep *instructionStep = [instructions firstObject];
|
|
XCTAssertEqualObjects(instructionStep.title, @"Right Hand");
|
|
XCTAssertEqualObjects(instructionStep.text, @"Put your device on a flat surface. Use two fingers on your right hand to alternately tap the buttons on the screen. Tap one finger, then the other. Try to time your taps to be as even as possible. Keep tapping for 10 seconds.");
|
|
|
|
// Look for the activity step
|
|
NSArray *tappings = filteredSteps(@"tapping", @"right");
|
|
XCTAssertEqual(tappings.count, 1);
|
|
ORKStep *tappingStep = [tappings firstObject];
|
|
XCTAssertEqualObjects(tappingStep.text, @"Tap the buttons using your RIGHT hand.");
|
|
XCTAssertFalse(tappingStep.optional);
|
|
|
|
}
|
|
|
|
- (void)testTwoFingerTappingIntervalTaskWithIdentifier_TapHandOptionBoth {
|
|
NSUInteger leftCount = 0;
|
|
NSUInteger rightCount = 0;
|
|
NSUInteger totalCount = 100;
|
|
NSUInteger threshold = 30;
|
|
|
|
for (int ii = 0; ii < totalCount; ii++) {
|
|
ORKOrderedTask *task = [ORKOrderedTask twoFingerTappingIntervalTaskWithIdentifier:@"test"
|
|
intendedUseDescription:nil
|
|
duration:10
|
|
handOptions:ORKPredefinedTaskHandOptionBoth
|
|
options:0];
|
|
ORKStep * (^filteredSteps)(NSString*, NSString*) = ^(NSString *part1, NSString *part2) {
|
|
NSString *keyValue = [NSString stringWithFormat:@"%@.%@", part1, part2];
|
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", NSStringFromSelector(@selector(identifier)), keyValue];
|
|
return [[task.steps filteredArrayUsingPredicate:predicate] firstObject];
|
|
};
|
|
|
|
// Look for instruction steps
|
|
ORKStep *rightInstructionStep = filteredSteps(@"instruction1", @"right");
|
|
XCTAssertNotNil(rightInstructionStep);
|
|
ORKStep *leftInstructionStep = filteredSteps(@"instruction1", @"left");
|
|
XCTAssertNotNil(leftInstructionStep);
|
|
|
|
// Depending upon the seed (clock time) this will be either the right or left hand
|
|
// Without using OCMock, cannot easily verify that both will display.
|
|
BOOL isRightFirst = [task.steps indexOfObject:rightInstructionStep] < [task.steps indexOfObject:leftInstructionStep];
|
|
if (isRightFirst) {
|
|
rightCount++;
|
|
} else {
|
|
leftCount++;
|
|
}
|
|
|
|
if ((isRightFirst && rightCount == 1) || (!isRightFirst && leftCount == 1)) {
|
|
|
|
// Look for instruction steps
|
|
XCTAssertEqualObjects(rightInstructionStep.title, @"Right Hand");
|
|
XCTAssertEqualObjects(leftInstructionStep.title, @"Left Hand");
|
|
|
|
// Depending upon the seed (clock time) this will be either the right or left hand
|
|
// Without using OCMock, cannot easily verify that both will display.
|
|
if (isRightFirst) {
|
|
XCTAssertEqualObjects(rightInstructionStep.text, @"Put your device on a flat surface. Use two fingers on your right hand to alternately tap the buttons on the screen. Tap one finger, then the other. Try to time your taps to be as even as possible. Keep tapping for 10 seconds.");
|
|
XCTAssertEqualObjects(leftInstructionStep.text, @"Put your device on a flat surface. Now repeat the same test using your left hand. Tap one finger, then the other. Try to time your taps to be as even as possible. Keep tapping for 10 seconds.");
|
|
} else {
|
|
XCTAssertEqualObjects(leftInstructionStep.text, @"Put your device on a flat surface. Use two fingers on your left hand to alternately tap the buttons on the screen. Tap one finger, then the other. Try to time your taps to be as even as possible. Keep tapping for 10 seconds.");
|
|
XCTAssertEqualObjects(rightInstructionStep.text, @"Put your device on a flat surface. Now repeat the same test using your right hand. Tap one finger, then the other. Try to time your taps to be as even as possible. Keep tapping for 10 seconds.");
|
|
}
|
|
|
|
// Look for tapping steps
|
|
ORKStep *rightTapStep = filteredSteps(@"tapping", @"right");
|
|
XCTAssertNotNil(rightTapStep);
|
|
XCTAssertEqualObjects(rightTapStep.text, @"Tap the buttons using your RIGHT hand.");
|
|
XCTAssertTrue(rightTapStep.optional);
|
|
|
|
ORKStep *leftTapStep = filteredSteps(@"tapping", @"left");
|
|
XCTAssertNotNil(leftTapStep);
|
|
XCTAssertEqualObjects(leftTapStep.text, @"Tap the buttons using your LEFT hand.");
|
|
XCTAssertTrue(leftTapStep.optional);
|
|
}
|
|
}
|
|
|
|
XCTAssertGreaterThan(leftCount, threshold);
|
|
XCTAssertGreaterThan(rightCount, threshold);
|
|
}
|
|
|
|
|
|
#pragma mark - Test Tremor Task navigation
|
|
|
|
- (void)testKeyValueStepModifier {
|
|
|
|
// Setup the task
|
|
ORKStep *boolStep = [ORKQuestionStep questionStepWithIdentifier:@"question"
|
|
title:@"Question"
|
|
question:@"Yes or No"
|
|
answer:[ORKAnswerFormat booleanAnswerFormat]];
|
|
|
|
ORKStep *nextStep = [[ORKInstructionStep alloc] initWithIdentifier:@"nextStep"];
|
|
nextStep.title = @"Yes";
|
|
|
|
ORKNavigableOrderedTask *task = [[ORKNavigableOrderedTask alloc] initWithIdentifier:NavigableOrderedTaskIdentifier
|
|
steps:@[boolStep, nextStep]];
|
|
|
|
ORKResultSelector *resultSelector = [ORKResultSelector selectorWithStepIdentifier:@"question"
|
|
resultIdentifier:@"question"];
|
|
NSPredicate *predicate = [ORKResultPredicate predicateForBooleanQuestionResultWithResultSelector:resultSelector
|
|
expectedAnswer:NO];
|
|
ORKStepModifier *stepModifier = [[ORKKeyValueStepModifier alloc] initWithResultPredicate:predicate
|
|
keyValueMap:@{ @"title" : @"No" }];
|
|
|
|
[task setStepModifier:stepModifier forStepIdentifier:@"nextStep"];
|
|
|
|
// -- Check the title if the answer is YES
|
|
ORKBooleanQuestionResult *result = [[ORKBooleanQuestionResult alloc] initWithIdentifier:@"question"];
|
|
result.booleanAnswer = @(YES);
|
|
ORKStepResult *stepResult = [[ORKStepResult alloc] initWithStepIdentifier:@"question" results:@[result]];
|
|
ORKTaskResult *taskResult = [[ORKTaskResult alloc] initWithTaskIdentifier:NavigableOrderedTaskIdentifier taskRunUUID:[NSUUID UUID] outputDirectory:nil];
|
|
taskResult.results = @[stepResult];
|
|
|
|
// For the case where the answer is YES, then the title should be "Yes" (unmodified)
|
|
ORKStep *yesStep = [task stepAfterStep:boolStep withResult:taskResult];
|
|
XCTAssertEqualObjects(yesStep.title, @"Yes");
|
|
|
|
// -- Check the title if the answer is NO
|
|
result.booleanAnswer = @(NO);
|
|
stepResult = [[ORKStepResult alloc] initWithStepIdentifier:@"question" results:@[result]];
|
|
taskResult.results = @[stepResult];
|
|
|
|
// For the case where the answer is NO, then the title should be modified to be "No"
|
|
ORKStep *noStep = [task stepAfterStep:boolStep withResult:taskResult];
|
|
XCTAssertEqualObjects(noStep.title, @"No");
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
|
|
@implementation MethodObject
|
|
@end
|
|
|
|
@implementation TestTaskViewControllerDelegate
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
_methodCalled = [NSMutableArray new];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)taskViewController:(ORKTaskViewController *)taskViewController didFinishWithReason:(ORKTaskFinishReason)reason error:(NSError *)error {
|
|
|
|
// Add results of method call
|
|
MethodObject *obj = [[MethodObject alloc] init];
|
|
obj.selectorName = NSStringFromSelector(@selector(taskViewController:didFinishWithReason:error:));
|
|
obj.arguments = @[taskViewController ?: [NSNull null],
|
|
@(reason),
|
|
error ?: [NSNull null]];
|
|
[self.methodCalled addObject:obj];
|
|
}
|
|
|
|
- (void)taskViewController:(ORKTaskViewController *)taskViewController stepViewControllerWillDisappear:(ORKStepViewController *)stepViewController navigationDirection:(ORKStepViewControllerNavigationDirection)direction {
|
|
// Add results of method call
|
|
MethodObject *obj = [[MethodObject alloc] init];
|
|
obj.selectorName = NSStringFromSelector(@selector(taskViewController:stepViewControllerWillDisappear:navigationDirection:));
|
|
obj.arguments = @[taskViewController ?: [NSNull null],
|
|
stepViewController ?: [NSNull null],
|
|
@(direction)];
|
|
[self.methodCalled addObject:obj];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MockTaskViewController
|
|
|
|
- (void)flipToNextPageFrom:(ORKStepViewController *)fromController {
|
|
// Add results of method call
|
|
MethodObject *obj = [[MethodObject alloc] init];
|
|
obj.selectorName = NSStringFromSelector(@selector(flipToNextPageFrom:));
|
|
obj.arguments = @[fromController ?: [NSNull null]];
|
|
[self.methodCalled addObject:obj];
|
|
}
|
|
|
|
- (void)flipToPreviousPageFrom:(ORKStepViewController *)fromController {
|
|
// Add results of method call
|
|
MethodObject *obj = [[MethodObject alloc] init];
|
|
obj.selectorName = NSStringFromSelector(@selector(flipToPreviousPageFrom:));
|
|
obj.arguments = @[fromController ?: [NSNull null]];
|
|
[self.methodCalled addObject:obj];
|
|
}
|
|
|
|
- (BOOL)hasSaveableResults {
|
|
BOOL result = NO;
|
|
|
|
if (self.overrideHasSaveableResults == nil) {
|
|
result = [super hasSaveableResults];
|
|
} else {
|
|
result = self.overrideHasSaveableResults.boolValue;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
@end
|