summaryrefslogtreecommitdiff
path: root/test/ios/LocationMocker
diff options
context:
space:
mode:
Diffstat (limited to 'test/ios/LocationMocker')
-rw-r--r--test/ios/LocationMocker/CLLocationManager+MockLocation.h39
-rw-r--r--test/ios/LocationMocker/CLLocationManager+MockLocation.m81
-rw-r--r--test/ios/LocationMocker/CSSwizzler.h22
-rw-r--r--test/ios/LocationMocker/CSSwizzler.m44
-rw-r--r--test/ios/LocationMocker/LocationMocker.h25
-rw-r--r--test/ios/LocationMocker/LocationMocker.m35
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