main
  1//
  2// Licensed under the terms in License.txt
  3//
  4// Copyright 2010 Allen Ding. All rights reserved.
  5//
  6
  7#import "KWBeWithinMatcher.h"
  8#import "KWFormatter.h"
  9#import "KWObjCUtilities.h"
 10#import "KWValue.h"
 11
 12@interface KWBeWithinMatcher()
 13
 14#pragma mark -
 15#pragma mark Properties
 16
 17@property (nonatomic, readwrite, retain) id distance;
 18@property (nonatomic, readwrite, retain) id otherValue;
 19
 20@end
 21
 22@implementation KWBeWithinMatcher
 23
 24#pragma mark -
 25#pragma mark Initializing
 26
 27- (void)dealloc {
 28    [distance release];
 29    [otherValue release];
 30    [super dealloc];
 31}
 32
 33#pragma mark -
 34#pragma mark Properties
 35
 36@synthesize distance;
 37@synthesize otherValue;
 38
 39#pragma mark -
 40#pragma mark Getting Matcher Strings
 41
 42+ (NSArray *)matcherStrings {
 43    return @[@"beWithin:of:", @"equal:withDelta:"];
 44}
 45
 46#pragma mark -
 47#pragma mark Matching
 48
 49// Evaluation is done by getting the underlying values as the widest data
 50// types available.
 51
 52- (BOOL)evaluateForFloatingPoint {
 53    double firstValue = [self.subject doubleValue];
 54    double secondValue = [self.otherValue doubleValue];
 55    double theDistance = [self.distance doubleValue];
 56    double absoluteDifference = firstValue > secondValue ? firstValue - secondValue : secondValue - firstValue;
 57    return absoluteDifference <= theDistance;
 58}
 59
 60- (BOOL)evaluateForUnsignedIntegral {
 61    unsigned long long firstValue = [self.subject unsignedLongLongValue];
 62    unsigned long long secondValue = [self.otherValue unsignedLongLongValue];
 63    unsigned long long theDistance = [self.distance unsignedLongLongValue];
 64    unsigned long long absoluteDifference = firstValue > secondValue ? firstValue - secondValue : secondValue - firstValue;
 65    return absoluteDifference <= theDistance;
 66}
 67
 68- (BOOL)evaluateForSignedIntegral {
 69    long long firstValue = [self.subject longLongValue];
 70    long long secondValue = [self.otherValue longLongValue];
 71    long long theDistance = [self.distance longLongValue];
 72    long long absoluteDifference = firstValue > secondValue ? firstValue - secondValue : secondValue - firstValue;
 73    return absoluteDifference <= theDistance;
 74}
 75
 76- (BOOL)evaluate {
 77    const char *objCType = [self.subject objCType];
 78
 79    if (KWObjCTypeIsFloatingPoint(objCType))
 80        return [self evaluateForFloatingPoint];
 81    else if (KWObjCTypeIsUnsignedIntegral(objCType))
 82        return [self evaluateForUnsignedIntegral];
 83    else
 84        return [self evaluateForSignedIntegral];
 85}
 86
 87#pragma mark -
 88#pragma mark Getting Failure Messages
 89
 90- (NSString *)failureMessageForShould {
 91    return [NSString stringWithFormat:@"expected subject to be within %@ of %@, got %@",
 92                                      [KWFormatter formatObject:self.distance],
 93                                      [KWFormatter formatObject:self.otherValue],
 94                                      [KWFormatter formatObject:self.subject]];
 95}
 96
 97- (NSString *)description
 98{
 99  return [NSString stringWithFormat:@"be within %@ of %@", self.distance, self.otherValue];
100}
101
102#pragma mark -
103#pragma mark Configuring Matchers
104
105- (void)beWithin:(id)aDistance of:(id)aValue {
106    self.distance = aDistance;
107    self.otherValue = aValue;
108}
109
110- (void)equal:(double)aValue withDelta:(double)aDelta {
111    [self beWithin:[KWValue valueWithDouble:aDelta] of:[KWValue valueWithDouble:aValue]];
112}
113
114@end