diff options
Diffstat (limited to 'test/ios/LocationMocker')
-rw-r--r-- | test/ios/LocationMocker/CLLocationManager+MockLocation.h | 39 | ||||
-rw-r--r-- | test/ios/LocationMocker/CLLocationManager+MockLocation.m | 81 | ||||
-rw-r--r-- | test/ios/LocationMocker/CSSwizzler.h | 22 | ||||
-rw-r--r-- | test/ios/LocationMocker/CSSwizzler.m | 44 | ||||
-rw-r--r-- | test/ios/LocationMocker/LocationMocker.h | 25 | ||||
-rw-r--r-- | test/ios/LocationMocker/LocationMocker.m | 35 |
6 files changed, 246 insertions, 0 deletions
diff --git a/test/ios/LocationMocker/CLLocationManager+MockLocation.h b/test/ios/LocationMocker/CLLocationManager+MockLocation.h new file mode 100644 index 0000000000..48641d0291 --- /dev/null +++ b/test/ios/LocationMocker/CLLocationManager+MockLocation.h @@ -0,0 +1,39 @@ +// +// Based on gist by Eric Allam +// https://gist.github.com/ericallam/5689235 +// + +#import <CoreLocation/CoreLocation.h> + +@interface CLLocationManager (MockLocation) + +- (void)custom_startUpdatingLocation; +- (CLLocation *)custom_location; + +- (void)custom_startUpdatingHeading; +- (CLHeading *)custom_heading; ++ (BOOL)custom_headingAvailable; + +@end + +// private setter struct for CLHeading +typedef struct { + double x; + double y; + double z; + double magneticHeading; + double trueHeading; + double accuracy; + double timestamp; + double temperature; + double magnitude; + double inclination; + int calibration; +} CLHeadingStruct; + +// create reference to private API method +@interface CLHeading () + +- (id)initWithClientHeading:(CLHeadingStruct)heading; + +@end diff --git a/test/ios/LocationMocker/CLLocationManager+MockLocation.m b/test/ios/LocationMocker/CLLocationManager+MockLocation.m new file mode 100644 index 0000000000..8937a5e0af --- /dev/null +++ b/test/ios/LocationMocker/CLLocationManager+MockLocation.m @@ -0,0 +1,81 @@ +// +// Based on gist by Eric Allam +// https://gist.github.com/ericallam/5689235 +// + +#import "CLLocationManager+MockLocation.h" +#import "LocationMocker.h" + +// This category implements methods that will be swizzled to replace key methods +// in CLLocationManager to mock out the user location. +@implementation CLLocationManager (MockLocation) + +// Replaces startUpdatingLocation, will send the locationManager:didUpdateLocations: message +// to the delegate after a wait of 0.1 seconds using dispatch_after to simulate how +// startUpdatingLocation actually works. This will not simulate any kind of location errors. +- (void)custom_startUpdatingLocation +{ + if (self.delegate) + { + if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) + { + // delay the locationManager:didUpdateLocations: message 0.1 seconds + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + NSArray *locations = @[self.location]; + [self.delegate locationManager:self didUpdateLocations:locations]; + }); + } + + if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateToLocation:fromLocation:)]) + { + // delay the locationManager:didUpdateToLocation:fromLocation: message 0.1 seconds + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self.delegate locationManager:self didUpdateToLocation:self.location fromLocation:nil]; + #pragma clang diagnostic pop + }); + } + } +} + +// Replaces location, returns the mocked CLLocation object +- (CLLocation *)custom_location; +{ + return [[CLLocation alloc] initWithLatitude:kMockedLatitude longitude:kMockedLongitude]; +} + + +// Replaces startUpdatingHeading, sends locationManager:didUpdateHeading: +- (void)custom_startUpdatingHeading +{ + if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateHeading:)]) + { + // delay the locationManager:didUpdateHeading: message 0.1 seconds + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self.delegate locationManager:self didUpdateHeading:self.heading]; + }); + } +} + +// Replaces heading, returns the mocked CLHeading object +- (CLHeading *)custom_heading; +{ + CLHeadingStruct heading; + heading.accuracy = kMockedHeadingAccuracy; + heading.trueHeading = kMockedHeadingTrueHeading; + heading.magneticHeading = kMockedHeadingMagneticHeading; + heading.x = kMockedHeadingX; + heading.y = kMockedHeadingY; + heading.z = kMockedHeadingZ; + + return [[CLHeading alloc] initWithClientHeading:heading]; +} + ++ (BOOL)custom_headingAvailable +{ + return YES; +} + +@end + diff --git a/test/ios/LocationMocker/CSSwizzler.h b/test/ios/LocationMocker/CSSwizzler.h new file mode 100644 index 0000000000..d0a2cc205c --- /dev/null +++ b/test/ios/LocationMocker/CSSwizzler.h @@ -0,0 +1,22 @@ +// +// Based on gist by Eric Allam +// https://gist.github.com/ericallam/5689235 +// + +#import <Foundation/Foundation.h> + +@interface CSSwizzler : NSObject + ++ (void)swizzleClass:(id)cls + replaceClassMethod:(SEL)origMethodSelector + withMethod:(SEL)replacementMethodSelector; + ++ (void)swizzleClass:(id)cls + replaceMethod:(SEL)origMethodSelector + withMethod:(SEL)replacementMethodSelector; + ++ (void)swizzleClassOfInstance:(id)inst + replaceMethod:(SEL)origMethodSelector + withMethod:(SEL)replacementMethodSelector; + +@end diff --git a/test/ios/LocationMocker/CSSwizzler.m b/test/ios/LocationMocker/CSSwizzler.m new file mode 100644 index 0000000000..70c5b12bc1 --- /dev/null +++ b/test/ios/LocationMocker/CSSwizzler.m @@ -0,0 +1,44 @@ +// +// Based on gist by Eric Allam +// https://gist.github.com/ericallam/5689235 +// + +#import "CSSwizzler.h" +#import <objc/message.h> +#import <objc/runtime.h> + +@implementation CSSwizzler + ++ (void)swizzleClass:(id)cls + replaceClassMethod:(SEL)origMethodSelector + withMethod:(SEL)replacementMethodSelector; +{ + Method origMethod = nil, altMethod = nil; + origMethod = class_getClassMethod(cls, origMethodSelector); + altMethod = class_getClassMethod(cls, replacementMethodSelector); + method_exchangeImplementations(origMethod, altMethod); +} + ++ (void)swizzleClass:(id)cls + replaceMethod:(SEL)origMethodSelector + withMethod:(SEL)replacementMethodSelector; +{ + Method origMethod = nil, altMethod = nil; + origMethod = class_getInstanceMethod(cls, origMethodSelector); + altMethod = class_getInstanceMethod(cls, replacementMethodSelector); + method_exchangeImplementations(origMethod, altMethod); +} + ++ (void)swizzleClassOfInstance:(id)inst + replaceMethod:(SEL)origMethodSelector + withMethod:(SEL)replacementMethodSelector; +{ + const char *str = [[[inst class] description] UTF8String]; + Class cls = objc_getClass(str); + Method origMethod = nil, altMethod = nil; + origMethod = class_getInstanceMethod(cls, origMethodSelector); + altMethod = class_getInstanceMethod(cls, replacementMethodSelector); + method_exchangeImplementations(origMethod, altMethod); +} + +@end diff --git a/test/ios/LocationMocker/LocationMocker.h b/test/ios/LocationMocker/LocationMocker.h new file mode 100644 index 0000000000..14f1dea75f --- /dev/null +++ b/test/ios/LocationMocker/LocationMocker.h @@ -0,0 +1,25 @@ +// +// Based on gist by Eric Allam +// https://gist.github.com/ericallam/5689235 +// + +#import <Foundation/Foundation.h> +#import <CoreLocation/CoreLocation.h> + +// lat and long of the mocked current location (Mapbox San Francisco) +static const CLLocationDegrees kMockedLatitude = 37.775716; +static const CLLocationDegrees kMockedLongitude = -122.413688; + +// heading (values pulled from south-facing device) +static const double kMockedHeadingAccuracy = 20.0; +static const double kMockedHeadingTrueHeading = 170.53; +static const double kMockedHeadingMagneticHeading = 154.83; +static const double kMockedHeadingX = -7.079; +static const double kMockedHeadingY = -16.548; +static const double kMockedHeadingZ = -44.194; + +@interface LocationMocker : NSObject + ++ (void)load; + +@end diff --git a/test/ios/LocationMocker/LocationMocker.m b/test/ios/LocationMocker/LocationMocker.m new file mode 100644 index 0000000000..a32270413c --- /dev/null +++ b/test/ios/LocationMocker/LocationMocker.m @@ -0,0 +1,35 @@ +// +// Based on gist by Eric Allam +// https://gist.github.com/ericallam/5689235 +// + +#import "LocationMocker.h" +#import "CSSwizzler.h" +#import "CLLocationManager+MockLocation.h" + +@implementation LocationMocker + ++ (void)load +{ + [CSSwizzler swizzleClass:[CLLocationManager class] + replaceMethod:@selector(startUpdatingLocation) + withMethod:@selector(custom_startUpdatingLocation)]; + + [CSSwizzler swizzleClass:[CLLocationManager class] + replaceMethod:@selector(location) + withMethod:@selector(custom_location)]; + + [CSSwizzler swizzleClass:[CLLocationManager class] + replaceMethod:@selector(startUpdatingHeading) + withMethod:@selector(custom_startUpdatingHeading)]; + + [CSSwizzler swizzleClass:[CLLocationManager class] + replaceMethod:@selector(heading) + withMethod:@selector(custom_heading)]; + + [CSSwizzler swizzleClass:[CLLocationManager class] + replaceClassMethod:@selector(headingAvailable) + withMethod:@selector(custom_headingAvailable)]; +} + +@end |