358 lines
13 KiB
Plaintext
358 lines
13 KiB
Plaintext
#import "../../../darwin/src/MLNGeometry_Private.h"
|
|
#import "MLNMapViewIntegrationTest.h"
|
|
#import "MLNTestUtility.h"
|
|
|
|
@interface MLNCameraTransitionTests : MLNMapViewIntegrationTest
|
|
@end
|
|
|
|
@implementation MLNCameraTransitionTests
|
|
|
|
- (void)testSetAndResetNorthWithDispatchAsyncInDelegateMethod {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
expectation.expectedFulfillmentCount = 2;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
|
|
if (!strongSelf) return;
|
|
|
|
[expectation fulfill];
|
|
|
|
MLNTestAssert(strongSelf, mapView.userTrackingMode != MLNUserTrackingModeFollowWithHeading);
|
|
if (mapView.direction != 0.0) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[mapView resetNorth];
|
|
});
|
|
}
|
|
};
|
|
|
|
[self.mapView setDirection:90 animated:YES];
|
|
|
|
// loop, render, and wait
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
}
|
|
|
|
- (void)testSetAndResetNorthInDelegateMethod {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
expectation.expectedFulfillmentCount = 2;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
|
|
if (!strongSelf) return;
|
|
|
|
[expectation fulfill];
|
|
|
|
MLNTestAssert(strongSelf, mapView.userTrackingMode != MLNUserTrackingModeFollowWithHeading);
|
|
if (mapView.direction != 0.0) {
|
|
NSLog(@"Reset to north");
|
|
[mapView resetNorth];
|
|
}
|
|
};
|
|
|
|
[self.mapView setDirection:90 animated:YES];
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
}
|
|
|
|
- (void)testInterruptingAndResetNorthOnlyOnceInIsChanging {
|
|
// Reset to non-zero, prior to testing
|
|
[self.mapView setDirection:45 animated:NO];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
expectation.expectedFulfillmentCount = 1;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
__block BOOL startedReset = NO;
|
|
__block BOOL finishedReset = NO;
|
|
|
|
self.regionIsChanging = ^(MLNMapView *mapView) {
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
if (!strongSelf) return;
|
|
|
|
if (!startedReset) {
|
|
NSLog(@"Reset to north, interrupting the previous transition");
|
|
startedReset = YES;
|
|
[mapView resetNorth];
|
|
finishedReset = YES;
|
|
}
|
|
};
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
if (!strongSelf) return;
|
|
|
|
MLNTestAssert(strongSelf, startedReset);
|
|
|
|
if (finishedReset) {
|
|
MLNTestAssert(strongSelf, !(reason & MLNCameraChangeReasonTransitionCancelled));
|
|
[expectation fulfill];
|
|
} else {
|
|
MLNTestAssert(strongSelf, reason & MLNCameraChangeReasonTransitionCancelled);
|
|
}
|
|
};
|
|
|
|
[self.mapView setDirection:90 animated:YES];
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
|
|
XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001,
|
|
@"Camera should have reset to north. %0.3f", self.mapView.direction);
|
|
}
|
|
|
|
- (void)testSetCenterCancelsTransitions {
|
|
XCTestExpectation *cameraIsInDCExpectation =
|
|
[self expectationWithDescription:@"camera reset to DC"];
|
|
|
|
CLLocationCoordinate2D dc = CLLocationCoordinate2DMake(38.894368, -77.036487);
|
|
CLLocationCoordinate2D dc_west = CLLocationCoordinate2DMake(38.894368, -77.076487);
|
|
|
|
double zoomLevel = 15.0;
|
|
|
|
[self.mapView setCenterCoordinate:dc zoomLevel:zoomLevel animated:NO];
|
|
[self.mapView setCenterCoordinate:dc_west zoomLevel:zoomLevel animated:YES];
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
|
|
dispatch_after(
|
|
dispatch_time(DISPATCH_TIME_NOW, 0.15 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
|
|
[strongSelf.mapView setCenterCoordinate:dc zoomLevel:zoomLevel animated:NO];
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, dc.latitude,
|
|
strongSelf.mapView.centerCoordinate.latitude, 0.0005,
|
|
@"setting center coordinate should cancel transitions");
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, dc.longitude,
|
|
strongSelf.mapView.centerCoordinate.longitude, 0.0005,
|
|
@"setting center coordinate should cancel transitions");
|
|
[cameraIsInDCExpectation fulfill];
|
|
});
|
|
|
|
[self waitForExpectations:@[ cameraIsInDCExpectation ] timeout:10.0];
|
|
}
|
|
|
|
- (void)testSetCenterCoordinateInDelegateMethod {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
expectation.expectedFulfillmentCount = 2;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
__block NSInteger delegateCallCount = 0;
|
|
|
|
CLLocationCoordinate2D target = CLLocationCoordinate2DMake(40.0, 40.0);
|
|
CLLocationCoordinate2D target2 = CLLocationCoordinate2DMake(-40.0, -40.0);
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
|
|
if (!strongSelf) return;
|
|
|
|
MLNTestAssert(strongSelf, mapView.userTrackingMode != MLNUserTrackingModeFollowWithHeading);
|
|
|
|
CLLocationCoordinate2D center = mapView.centerCoordinate;
|
|
|
|
switch (delegateCallCount) {
|
|
case 0: {
|
|
// Our center coordinate should match our target (assuming we're not
|
|
// constrained by zoom level)
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target.longitude, center.longitude, 0.0005,
|
|
@"center coordinate longitude should be at target");
|
|
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target.latitude, center.latitude, 0.0005,
|
|
@"center coordinate latitude should be at target");
|
|
|
|
// Now set another coordinate.
|
|
// Should take MLNAnimationDuration seconds (0.3s)
|
|
[mapView setCenterCoordinate:target2 animated:YES];
|
|
break;
|
|
}
|
|
|
|
case 1: {
|
|
// Our center coordinate should match our target (assuming we're not
|
|
// constrained by zoom level)
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target2.longitude, center.longitude, 0.0005,
|
|
@"center coordinate longitude should be at target2");
|
|
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target2.latitude, center.latitude, 0.0005,
|
|
@"center coordinate latitude should be at target2");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MLNTestFail(strongSelf);
|
|
break;
|
|
}
|
|
|
|
delegateCallCount++;
|
|
|
|
[expectation fulfill];
|
|
};
|
|
|
|
// Should take MLNAnimationDuration seconds (0.3)
|
|
[self.mapView setCenterCoordinate:target zoomLevel:15.0 animated:YES];
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
}
|
|
|
|
- (void)testFlyToCameraInDelegateMethod {
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
__block NSInteger delegateCallCount = 0;
|
|
expectation.expectedFulfillmentCount = 3;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
CLLocationCoordinate2D target = CLLocationCoordinate2DMake(40.0, 40.0);
|
|
CLLocationCoordinate2D target2 = CLLocationCoordinate2DMake(30.0, 30.0);
|
|
|
|
__block BOOL runloop = YES;
|
|
|
|
NSTimeInterval stop0 = CACurrentMediaTime();
|
|
__block NSTimeInterval stop1 = 0.0;
|
|
__block NSTimeInterval stop2 = 0.0;
|
|
|
|
double zoomLevel = 5.0;
|
|
double altitude =
|
|
MLNAltitudeForZoomLevel(zoomLevel, 0.0, target.latitude, self.mapView.frame.size);
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
MLNCameraTransitionTests *strongSelf = weakself;
|
|
|
|
if (!strongSelf) return;
|
|
|
|
MLNTestAssert(strongSelf, mapView.userTrackingMode != MLNUserTrackingModeFollowWithHeading);
|
|
|
|
CLLocationCoordinate2D center = mapView.centerCoordinate;
|
|
|
|
switch (delegateCallCount) {
|
|
case 0: {
|
|
stop1 = CACurrentMediaTime();
|
|
|
|
// Our center coordinate should match our target (assuming we're not
|
|
// constrained by zoom level)
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target.longitude, center.longitude, 0.0005,
|
|
@"center coordinate longitude should be at target");
|
|
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target.latitude, center.latitude, 0.0005,
|
|
@"center coordinate latitude should be at target");
|
|
|
|
// Now set another coordinate.
|
|
MLNMapCamera *camera = [MLNMapCamera cameraLookingAtCenterCoordinate:target2
|
|
altitude:altitude
|
|
pitch:0.0
|
|
heading:0.0];
|
|
|
|
// flyToCamera can take a while...
|
|
[mapView flyToCamera:camera
|
|
completionHandler:^{
|
|
MLNTestAssert(strongSelf, !runloop,
|
|
@"Completion block should be called after delegate method");
|
|
[expectation fulfill];
|
|
stop2 = CACurrentMediaTime();
|
|
}];
|
|
break;
|
|
}
|
|
|
|
case 1: {
|
|
// Our center coordinate should match our target (assuming we're not
|
|
// constrained by zoom level)
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target2.longitude, center.longitude, 0.0005,
|
|
@"center coordinate longitude should be at target2");
|
|
|
|
MLNTestAssertEqualWithAccuracy(strongSelf, target2.latitude, center.latitude, 0.0005,
|
|
@"center coordinate latitude should be at target2");
|
|
|
|
runloop = NO;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MLNTestFail(strongSelf);
|
|
break;
|
|
}
|
|
|
|
delegateCallCount++;
|
|
|
|
[expectation fulfill];
|
|
};
|
|
|
|
// Should take MLNAnimationDuration
|
|
[self.mapView setCenterCoordinate:target zoomLevel:zoomLevel animated:YES];
|
|
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
|
|
NSLog(@"setCenterCoordinate: %0.4fs", stop1 - stop0);
|
|
NSLog(@"flyToCamera: %0.4fs", stop2 - stop1);
|
|
|
|
XCTAssert(delegateCallCount == 2, @"Expecting 2 regionDidChange callbacks, got %ld",
|
|
(long)delegateCallCount); // Once for the setDirection and once for the reset north
|
|
}
|
|
|
|
// MARK: - Pending tests
|
|
|
|
- (void)testContinuallyResettingNorthInIsChangingPENDING {
|
|
// See https://github.com/mapbox/mapbox-gl-native/pull/11614
|
|
// This test currently fails, unsurprisingly, since we're continually
|
|
// setting the camera to the same parameters during its update.
|
|
//
|
|
// Possible solutions/expectations:
|
|
// - If you set camera parameters that match the *current* target parameters
|
|
// then the transition could be a no-op. We'd need to consider any completion
|
|
// block
|
|
// - Ideally we would detect this case and disallow it.
|
|
|
|
// Reset to non-zero, prior to testing
|
|
[self.mapView setDirection:45 animated:NO];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
expectation.expectedFulfillmentCount = 2;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
self.regionIsChanging = ^(MLNMapView *mapView) {
|
|
[mapView resetNorth];
|
|
};
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
[expectation fulfill];
|
|
};
|
|
|
|
[self.mapView setDirection:90 animated:YES];
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
|
|
XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001,
|
|
@"Camera should have reset to north. %0.3f", self.mapView.direction);
|
|
}
|
|
|
|
- (void)testContinuallySettingCoordinateInIsChangingPENDING {
|
|
// See above comment in `-testContinuallyResettingNorthInIsChangingPENDING`
|
|
|
|
// Reset to non-zero, prior to testing
|
|
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(0.0, 0.0) animated:NO];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
|
|
expectation.expectedFulfillmentCount = 2;
|
|
expectation.assertForOverFulfill = YES;
|
|
|
|
__weak MLNCameraTransitionTests *weakself = self;
|
|
|
|
self.regionIsChanging = ^(MLNMapView *mapView) {
|
|
[weakself.mapView setCenterCoordinate:CLLocationCoordinate2DMake(-40.0, -40.0) animated:YES];
|
|
};
|
|
|
|
self.regionDidChange = ^(MLNMapView *mapView, MLNCameraChangeReason reason, BOOL animated) {
|
|
[expectation fulfill];
|
|
};
|
|
|
|
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(40.0, 40.0) animated:YES];
|
|
[self waitForExpectations:@[ expectation ] timeout:10];
|
|
|
|
XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001,
|
|
@"Camera should have reset to north. %0.3f", self.mapView.direction);
|
|
}
|
|
|
|
@end
|