diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2020-02-27 13:09:39 -0800 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2020-02-27 17:14:20 -0800 |
commit | 206b9bde5ed9204de6ec18c0d37495db7c30aa09 (patch) | |
tree | 0049d4d6bd9195c194c0fe96665ba72c92f00da5 /platform/ios/Integration Tests | |
parent | bd252e16a3574efd11cca57917f52e6d1b2dd0a2 (diff) | |
download | qtlocation-mapboxgl-206b9bde5ed9204de6ec18c0d37495db7c30aa09.tar.gz |
[ios, macos] Deleted iOS/macOS map SDK sources, resources, scripts
Diffstat (limited to 'platform/ios/Integration Tests')
17 files changed, 0 insertions, 3237 deletions
diff --git a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm deleted file mode 100644 index 1b3603419e..0000000000 --- a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm +++ /dev/null @@ -1,818 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" -#import "MGLTestUtility.h" -#import "MGLMapAccessibilityElement.h" -#import "MGLTestLocationManager.h" -#import "MGLCompactCalloutView.h" - -#import "MGLGeometry_Private.h" -#import "MGLMapView_Private.h" - -#include <mbgl/util/geo.hpp> -#include <mbgl/map/camera.hpp> -#include <mbgl/map/map.hpp> - -@interface MGLTestCalloutView : MGLCompactCalloutView -@property (nonatomic) BOOL implementsMarginHints; -@end - -@implementation MGLTestCalloutView -- (BOOL)respondsToSelector:(SEL)aSelector { - if (!self.implementsMarginHints && - (aSelector == @selector(marginInsetsHintForPresentationFromRect:))) { - return NO; - } - return [super respondsToSelector:aSelector]; -} -@end - - -@interface MGLMapView (Tests) -- (MGLAnnotationTag)annotationTagAtPoint:(CGPoint)point persistingResults:(BOOL)persist; -- (id <MGLAnnotation>)annotationWithTag:(MGLAnnotationTag)tag; -- (MGLMapCamera *)cameraByRotatingToDirection:(CLLocationDirection)degrees aroundAnchorPoint:(CGPoint)anchorPoint; -- (MGLMapCamera *)cameraByZoomingToZoomLevel:(double)zoom aroundAnchorPoint:(CGPoint)anchorPoint; -- (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions; -@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation; -@end - -@interface MGLAnnotationViewIntegrationTests : MGLMapViewIntegrationTest -@end - -@implementation MGLAnnotationViewIntegrationTests - -#pragma mark - Offscreen/panning selection tests - -typedef struct PanTestData { - CGPoint relativeCoord; - BOOL showsCallout; - BOOL implementsMargins; - BOOL moveIntoView; - BOOL expectMapToHavePanned; - BOOL calloutOnScreen; -} PanTestData; - -#define PAN_TEST_TERMINATOR {{FLT_MAX, FLT_MAX}, NO, NO, NO, NO, NO} -static const CGPoint kAnnotationRelativeScale = { 0.05f, 0.125f }; - -- (void)internalTestOffscreenSelectionTitle:(NSString*)title withTestData:(PanTestData)test animateSelection:(BOOL)animateSelection { - - CGPoint relativeCoordinate = test.relativeCoord; - BOOL showsCallout = test.showsCallout; - BOOL calloutImplementsMarginHints = test.implementsMargins; - BOOL moveIntoView = test.moveIntoView; - BOOL expectMapToHavePanned = test.expectMapToHavePanned; - BOOL expectCalloutToBeFullyOnscreen = test.calloutOnScreen; - - // Reset the map to a consistent state - want the map to be zoomed in, so that - // it's free to be panned without hitting boundaries. - [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(0, 0) zoomLevel:14 animated:NO]; - [self waitForMapViewToBeRenderedWithTimeout:1.0]; - - XCTAssert(self.mapView.annotations.count == 0); - - NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer"; - CGSize size = self.mapView.bounds.size; - CGSize annotationSize = CGSizeMake(floor(size.width*kAnnotationRelativeScale.x), floor(size.height*kAnnotationRelativeScale.y)); - - self.viewForAnnotation = ^MGLAnnotationView*(MGLMapView *view, id<MGLAnnotation> annotation) { - - if (![annotation isKindOfClass:[MGLPointAnnotation class]]) { - return nil; - } - - // No dequeue - MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MGLTestAnnotationReuseIdentifer]; - annotationView.bounds = (CGRect){ .origin = CGPointZero, .size = annotationSize }; - annotationView.backgroundColor = UIColor.redColor; - annotationView.enabled = YES; - - return annotationView; - }; - - // Coordinate for annotation screen coordinate - CGPoint annotationPoint = CGPointMake(floor(relativeCoordinate.x * size.width), floor(relativeCoordinate.y * size.height) ); - CLLocationCoordinate2D coordinate = [self.mapView convertPoint:annotationPoint toCoordinateFromView:self.mapView]; - - MGLPointAnnotation *point = [[MGLPointAnnotation alloc] init]; - point.title = title; - point.coordinate = coordinate; - - self.mapViewAnnotationCanShowCalloutForAnnotation = ^BOOL(MGLMapView *mapView, id<MGLAnnotation> annotation) { - return showsCallout; - }; - - self.mapViewCalloutViewForAnnotation = ^id<MGLCalloutView>(MGLMapView *mapView, id<MGLAnnotation> annotation) { - if (!showsCallout) - return nil; - - MGLTestCalloutView *calloutView = [[MGLTestCalloutView alloc] init]; - calloutView.representedObject = annotation; - calloutView.implementsMarginHints = calloutImplementsMarginHints; - return calloutView; - }; - - [self.mapView addAnnotation:point]; - - // Check assumptions before selection - UIView *annotationViewBeforeSelection = [self.mapView viewForAnnotation:point]; - XCTAssertNotNil(annotationViewBeforeSelection); - - CLLocationCoordinate2D mapCenterBeforeSelection = self.mapView.centerCoordinate; - XCTAssert(CLLocationCoordinate2DIsValid(mapCenterBeforeSelection)); - - // Also note, that at this point, the internal mechanism that determines if - // an annotation view is offscreen and should be put back in the reuse queue - // will have run, and `viewForAnnotation` may return nil - - XCTestExpectation *selectionCompleted = [self expectationWithDescription:@"Selection completed"]; - [self.mapView selectAnnotation:point moveIntoView:moveIntoView animateSelection:animateSelection completionHandler:^{ - [selectionCompleted fulfill]; - }]; - - // Animated selection takes MGLAnimationDuration (0.3 seconds), so wait a little - // longer. We don't need to wait as long if we're not animated (but we do - // want the runloop to tick over) - [self waitForExpectations:@[selectionCompleted] timeout:animateSelection ? 0.4: 0.05]; - - UIView *annotationViewAfterSelection = [self.mapView viewForAnnotation:point]; - CLLocationCoordinate2D mapCenterAfterSelection = self.mapView.centerCoordinate; - XCTAssert(CLLocationCoordinate2DIsValid(mapCenterAfterSelection)); - - // If the annotation is still "offscreen" at this point, then the above annotation view - // may be nil, which is expected. - BOOL (^CGRectContainsRectWithAccuracy)(CGRect, CGRect, CGFloat) = ^(CGRect rect1, CGRect rect2, CGFloat accuracy) { - CGRect expandedRect1 = CGRectInset(rect1, -accuracy, -accuracy); - return (BOOL)CGRectContainsRect(expandedRect1, rect2); - }; - - CGFloat epsilon = 0.00001; - if (expectMapToHavePanned) { - CLLocationDegrees latitudeDelta = fabs(mapCenterAfterSelection.latitude - mapCenterBeforeSelection.latitude); - CLLocationDegrees longitudeDelta = fabs(mapCenterAfterSelection.longitude - mapCenterBeforeSelection.longitude); - - XCTAssert( (latitudeDelta > epsilon) || (longitudeDelta > epsilon), @"Deltas: lat=%f, long=%f", latitudeDelta, longitudeDelta); // One of them should have moved - - // If the map panned - the intention is that the annotation is on-screen, - // and so should have an annotation view and that it is fully on screen - CGRect annotationFrameAfterSelection = annotationViewAfterSelection.frame; - - XCTAssertNotNil(annotationViewAfterSelection); - - XCTAssert(CGRectContainsRectWithAccuracy(self.mapView.bounds, annotationFrameAfterSelection, 0.25), @"Mapview:%@ frame:%@", NSStringFromCGRect(self.mapView.bounds), NSStringFromCGRect(annotationFrameAfterSelection)); - - // Check the callout - if (showsCallout) { - UIView *calloutView = self.mapView.calloutViewForSelectedAnnotation; - XCTAssertNotNil(calloutView); - - // This can fail if the callout view's width is < the annotations. This is really a warning, so - // if you need this NOT to fail the tests, consider replacing with MGLTestWarning - XCTAssert(expectCalloutToBeFullyOnscreen == CGRectContainsRectWithAccuracy(self.mapView.bounds, calloutView.frame, 0.25), - @"Expect contains:%d, Mapview:%@ annotation:%@ callout:%@", - expectCalloutToBeFullyOnscreen, - NSStringFromCGRect(self.mapView.bounds), - NSStringFromCGRect(annotationFrameAfterSelection), - NSStringFromCGRect(calloutView.frame)); - } - } - else { - // The map shouldn't have moved, so use equality (rather than an error check) - XCTAssertEqual(mapCenterBeforeSelection.latitude, mapCenterAfterSelection.latitude); - XCTAssertEqual(mapCenterBeforeSelection.longitude, mapCenterAfterSelection.longitude); - - // Annotation shouldn't have moved - CGPoint annotationPoint2 = [self.mapView convertCoordinate:point.coordinate toPointToView:self.mapView]; - CGFloat xDelta = fabs(annotationPoint2.x - annotationPoint.x); - CGFloat yDelta = fabs(annotationPoint2.y - annotationPoint.y); - - XCTAssert((xDelta < epsilon) && (yDelta < epsilon)); - - if (showsCallout) { - UIView *calloutView = self.mapView.calloutViewForSelectedAnnotation; - - if (annotationViewAfterSelection) { - XCTAssertNotNil(calloutView); - - // If kAnnotationScale == 0.25, then the following assert can fail. - // This is really a warning (see https://github.com/mapbox/mapbox-gl-native/issues/13744 ) - // If you need this NOT to fail the tests, consider replacing with MGLTestWarning - XCTAssert((expectCalloutToBeFullyOnscreen == CGRectContainsRectWithAccuracy(self.mapView.bounds, calloutView.frame, 0.25)), - @"Mapview:%@ annotation:%@ callout:%@", - NSStringFromCGRect(self.mapView.bounds), - NSStringFromCGRect(annotationViewAfterSelection.frame), - NSStringFromCGRect(calloutView.frame)); - } - else { - // If there's no annotation view, should we expect a callout? - XCTAssertNil(calloutView); - XCTAssertFalse(expectCalloutToBeFullyOnscreen); - } - } - } - - // Remove the annotation - [self.mapView removeAnnotation:point]; - - XCTAssert(self.mapView.annotations.count == 0); -} - -// See https://github.com/mapbox/mapbox-gl-native/pull/13727#issuecomment-454028698 -// What follows are tests based on this table. -// This is not a full-set of possible combinations, just the most important/likely -// ones -- (void)internalRunTests:(PanTestData*)testData -{ - // Test both animated and not-animated. - for (int i = 0; i<2; i++) { - int row = 0; - PanTestData *test = testData; - while (test->relativeCoord.x != FLT_MAX) { - NSString *activityTitle = [NSString stringWithFormat:@"Row %d/%d", row, i]; - [XCTContext runActivityNamed:activityTitle - block:^(id<XCTActivity> _Nonnull activity) { - [self internalTestOffscreenSelectionTitle:activityTitle - withTestData:*test - animateSelection:!i]; - }]; - ++test; - ++row; - } - } -} - -- (void)testBasicSelection { - // Tests moveIntoView:NO - // WITHOUT a callout - - PanTestData tests[] = { - // Coord showsCallout impl margins? moveIntoView expectMapToPan calloutOnScreen - // Offscreen - { {-1.0f, 0.5f}, NO, NO, NO, NO, NO }, - { { 2.0f, 0.5f}, NO, NO, NO, NO, NO }, - { { 0.5f,-1.0f}, NO, NO, NO, NO, NO }, - { { 0.5f, 2.0f}, NO, NO, NO, NO, NO }, - - // Partial - { { 0.0f, 0.5f}, NO, NO, NO, NO, NO }, - { { 1.0f, 0.5f}, NO, NO, NO, NO, NO }, - { { 0.5f, 0.0f}, NO, NO, NO, NO, NO }, - { { 0.5f, 1.0f}, NO, NO, NO, NO, NO }, - - // Onscreen - { { 0.5f, 0.5f}, NO, NO, NO, NO, NO }, - - PAN_TEST_TERMINATOR - }; - - [self internalRunTests:tests]; -} - -- (void)testBasicSelectionWithCallout { - // Tests moveIntoView:NO - // WITH the default callout (implements marginshint) - - PanTestData tests[] = { - // Coord showsCallout impl margins? moveIntoView expectMapToPan calloutOnScreen - { {-1.0f, 0.5f}, YES, YES, NO, NO, NO }, - { { 0.0f, 0.5f}, YES, YES, NO, NO, NO }, - { { 0.5f, 1.0f}, YES, YES, NO, NO, YES }, // Because annotation was off the bottom of screen, and callout is above annotation - { { 0.5f, 0.5f}, YES, YES, NO, NO, YES }, - - PAN_TEST_TERMINATOR - }; - - [self internalRunTests:tests]; -} - -- (void)testSelectionMoveIntoView { - // Tests moveIntoView:YES - // without a callout - - // From https://github.com/mapbox/mapbox-gl-native/pull/13727#issuecomment-454028698 - // - // | Annotation position | Has callout? | Callout implements `marginInsets...`? | Map pans when selected with moveIntoView=YES? | - // |---------------------|--------------|---------------------------------------|-----------------------------------------------| - // | Offscreen | No | n/a | Yes (no margins) | - // | Partially | No | n/a | No | - // | Onscreen | No | n/a | No | - // - - PanTestData tests[] = { - // Coord showsCallout impl margins? moveIntoView expectMapToPan calloutOnScreen - // Offscreen - { {-1.0f, 0.5f}, NO, NO, YES, YES, NO }, - { { 2.0f, 0.5f}, NO, NO, YES, YES, NO }, - { { 0.5f,-1.0f}, NO, NO, YES, YES, NO }, - { { 0.5f, 2.0f}, NO, NO, YES, YES, NO }, - - // Partial - { { 0.0f, 0.5f}, NO, NO, YES, NO, NO }, - { { 1.0f, 0.5f}, NO, NO, YES, NO, NO }, - { { 0.5f, 0.0f}, NO, NO, YES, NO, NO }, - { { 0.5f, 1.0f}, NO, NO, YES, NO, NO }, - - // Onscreen - { { 0.5f, 0.5f}, NO, NO, YES, NO, NO }, - - PAN_TEST_TERMINATOR - }; - - [self internalRunTests:tests]; -} - -- (void)testSelectionMoveIntoViewWithCallout { - // Tests moveIntoView:YES - // WITH the default callout (implements marginshint) - - // From https://github.com/mapbox/mapbox-gl-native/pull/13727#issuecomment-454028698 - // - // | Annotation position | Has callout? | Callout implements `marginInsets...`? | Map pans when selected with moveIntoView=YES? | - // |---------------------|--------------|---------------------------------------|-----------------------------------------------| - // | Offscreen | Yes | Yes | Yes to ensure callout is fully visible | - // | Partially | Yes | Yes | Yes to ensure callout is fully visible | - // | Onscreen | Yes | Yes | Yes, but *only* to ensure callout is fully visible | - // - - CGFloat offset = kAnnotationRelativeScale.x * 0.5f; - - PanTestData tests[] = { - // Coord showsCallout impl margins? moveIntoView expectMapToPan calloutOnScreen - // Offscreen - { {-1.0f, 0.5f}, YES, YES, YES, YES, YES }, - { { 2.0f, 0.5f}, YES, YES, YES, YES, YES }, - { { 0.5f,-1.0f}, YES, YES, YES, YES, YES }, - { { 0.5f, 2.0f}, YES, YES, YES, YES, YES }, - - // Partial - { { 0.0f, 0.5f}, YES, YES, YES, YES, YES }, - { { 1.0f, 0.5f}, YES, YES, YES, YES, YES }, - { { 0.5f, 0.0f}, YES, YES, YES, YES, YES }, - { { 0.5f, 1.0f}, YES, YES, YES, YES, YES }, - - // Onscreen - { { 0.5f, 0.5f}, YES, YES, YES, NO, YES }, - - // Just at the edge of the screen. - // Expects to move, because although onscreen, callout would not be. - // However, if the scale is 0.25, then expectToPan should be NO, because - // of the width of the annotation - - // Coord showsCallout impl margins? moveIntoView expectMapToPan calloutOnScreen - { {offset, 0.5f}, YES, YES, YES, YES, YES }, - { {1.0 - offset, 0.5f}, YES, YES, YES, YES, YES }, - - PAN_TEST_TERMINATOR - }; - - [self internalRunTests:tests]; -} - -- (void)testSelectionMoveIntoViewWithBasicCallout { - // Tests moveIntoView:YES - // WITH a callout that DOES NOT implement marginshint - - // From https://github.com/mapbox/mapbox-gl-native/pull/13727#issuecomment-454028698 - // - // | Annotation position | Has callout? | Callout implements `marginInsets...`? | Map pans when selected with moveIntoView=YES? | - // |---------------------|--------------|---------------------------------------|-----------------------------------------------| - // | Offscreen | Yes | No | Yes, but only to show annotation (not callout) with no margins | - // | Partially | Yes | No | No | - // | Onscreen | Yes | No | No | - // - - PanTestData tests[] = { - // Coord showsCallout impl margins? moveIntoView expectMapToPan calloutOnScreen - // Offscreen - { {-1.0f, 0.5f}, YES, NO, YES, YES, NO }, - { { 2.0f, 0.5f}, YES, NO, YES, YES, NO }, - { { 0.5f,-1.0f}, YES, NO, YES, YES, NO }, - { { 0.5f, 2.0f}, YES, NO, YES, YES, YES }, // Because annotation was off the bottom of screen, and callout is above annotation - { { 2.0f, 2.0f}, YES, NO, YES, YES, NO }, - - // Partial - { { 0.0f, 0.5f}, YES, NO, YES, NO, NO }, - { { 1.0f, 0.5f}, YES, NO, YES, NO, NO }, - { { 0.5f, 0.0f}, YES, NO, YES, NO, NO }, - { { 0.5f, 1.0f}, YES, NO, YES, NO, YES }, // Because annotation was off the bottom of screen, and callout is above annotation - { { 1.0f, 1.0f}, YES, NO, YES, NO, NO }, - - // Onscreen - { { 0.5f, 0.5f}, YES, NO, YES, NO, YES }, - - PAN_TEST_TERMINATOR - }; - - [self internalRunTests:tests]; -} - -#pragma mark - Selection with an offset - -- (void)testSelectingAnnotationWithCenterOffset { - - for (CGFloat dx = -100.0; dx <= 100.0; dx += 100.0 ) { - for (CGFloat dy = -100.0; dy <= 100.0; dy += 100.0 ) { - CGVector offset = CGVectorMake(dx, dy); - UIEdgeInsets edgeInsets = UIEdgeInsetsMake(fmax(-dy, 0.0), fmax(-dy, 0.0), fmax(dy, 0.0), fmax(dx, 0.0)); - [self internalTestSelectingAnnotationWithCenterOffsetWithOffset:offset edgeInsets:edgeInsets]; - } - } -} - -- (void)internalTestSelectingAnnotationWithCenterOffsetWithOffset:(CGVector)offset edgeInsets:(UIEdgeInsets)edgeInsets { - - NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer"; - - self.mapView.contentInset = edgeInsets; - CGSize size = self.mapView.bounds.size; - - CGSize annotationSize = CGSizeMake(40.0, 40.0); - - self.viewForAnnotation = ^MGLAnnotationView*(MGLMapView *view, id<MGLAnnotation> annotation) { - - if (![annotation isKindOfClass:[MGLPointAnnotation class]]) { - return nil; - } - - // No dequeue - MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MGLTestAnnotationReuseIdentifer]; - annotationView.bounds = (CGRect){ .origin = CGPointZero, .size = annotationSize }; - annotationView.backgroundColor = UIColor.redColor; - annotationView.enabled = YES; - annotationView.centerOffset = offset; - - return annotationView; - }; - - MGLPointAnnotation *point = [[MGLPointAnnotation alloc] init]; - point.title = NSStringFromSelector(_cmd); - point.coordinate = CLLocationCoordinate2DMake(0.0, 0.0); - [self.mapView addAnnotation:point]; - - // From https://github.com/mapbox/mapbox-gl-native/issues/12259#issuecomment-401414168 - // - // queryRenderedFeatures depends on collision detection having been run - // before it shows results [...]. Collision detection runs asynchronously - // (at least every 300ms, sometimes more often), and therefore the results - // of queryRenderedFeatures are similarly asynchronous. - // - // So, we need to wait before `annotationTagAtPoint:persistingResults:` will - // return out newly added annotation - - [self waitForCollisionDetectionToRun]; - - // Check that the annotation is in the center of the view - CGPoint annotationPoint = [self.mapView convertCoordinate:point.coordinate toPointToView:self.mapView]; - XCTAssertEqualWithAccuracy(annotationPoint.x, (size.width - edgeInsets.right + edgeInsets.left)/2.0, 0.25); - XCTAssertEqualWithAccuracy(annotationPoint.y, (size.height - edgeInsets.bottom + edgeInsets.top)/2.0, 0.25); - - // Now test taps around the annotation - CGPoint tapPoint = CGPointMake(annotationPoint.x + offset.dx, annotationPoint.y + offset.dy); - - MGLAnnotationTag tagAtPoint = [self.mapView annotationTagAtPoint:tapPoint persistingResults:YES]; - XCTAssert(tagAtPoint != UINT32_MAX, @"Should have tapped on annotation"); - - CGPoint testPoints[] = { - { tapPoint.x - annotationSize.width, tapPoint.y }, - { tapPoint.x + annotationSize.width, tapPoint.y }, - { tapPoint.x, tapPoint.y - annotationSize.height }, - { tapPoint.x, tapPoint.y + annotationSize.height }, - CGPointZero - }; - - CGPoint *testPoint = testPoints; - - while (!CGPointEqualToPoint(*testPoint, CGPointZero)) { - tagAtPoint = [self.mapView annotationTagAtPoint:*testPoints persistingResults:YES]; - XCTAssert(tagAtPoint == UINT32_MAX, @"Tap should to the side of the annotation"); - testPoint++; - } -} - -- (void)testUserLocationWithOffsetAnchorPoint { - [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(37.787357, -122.39899)]; - MGLTestLocationManager *locationManager = [[MGLTestLocationManager alloc] init]; - self.mapView.locationManager = locationManager; - - [self.mapView setUserTrackingMode:MGLUserTrackingModeFollow animated:NO completionHandler:nil]; - CGRect originalFrame = [self.mapView viewForAnnotation:self.mapView.userLocation].frame; - - // Temporarily disable location tracking so we can save the value of - // the originalFrame in memory - [self.mapView setUserTrackingMode:MGLUserTrackingModeNone animated:NO completionHandler:nil]; - - CGPoint offset = CGPointMake(20, 20); - - self.mapViewUserLocationAnchorPoint = ^CGPoint (MGLMapView *mapView) { - return offset;; - }; - - [self.mapView setUserTrackingMode:MGLUserTrackingModeFollow animated:NO completionHandler:nil]; - CGRect offsetFrame = [self.mapView viewForAnnotation:self.mapView.userLocation].frame; - - XCTAssertEqual(originalFrame.origin.x + offset.x, offsetFrame.origin.x); - XCTAssertEqual(originalFrame.origin.y + offset.y, offsetFrame.origin.y); -} - -#pragma mark - Rotating/zooming - -- (void)testSelectingAnnotationWhenMapIsRotated { - - CLLocationCoordinate2D coordinates[] = { - { 40.0, 40.0 }, - { NAN, NAN } - }; - - NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates]; - MGLPointAnnotation *annotation = annotations.firstObject; - - // Rotate - CLLocationDirection lastAngle = 0.0; - - srand48(0); - for (NSInteger iter = 0; iter < 10; iter++ ) { - - CLLocationDirection angle = (CLLocationDirection)((drand48()*1080.0) - 540.0); - - CGPoint anchor = CGPointMake(drand48()*CGRectGetWidth(self.mapView.bounds), drand48()*CGRectGetHeight(self.mapView.bounds)); - - NSString *activityTitle = [NSString stringWithFormat:@"Rotate to: %0.1f from: %0.1f", angle, lastAngle]; - [XCTContext runActivityNamed:activityTitle - block:^(id<XCTActivity> _Nonnull activity) { - - MGLMapCamera *toCamera = [self.mapView cameraByRotatingToDirection:angle aroundAnchorPoint:anchor]; - [self internalTestSelecting:annotation withCamera:toCamera]; - }]; - - lastAngle = angle; - } -} - -- (void)testSelectingAnnotationWhenMapIsScaled { - - CLLocationCoordinate2D coordinates[] = { - { 0.005, 0.005 }, - { NAN, NAN } - }; - - NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates]; - MGLPointAnnotation *annotation = annotations.firstObject; - - CGPoint anchor = CGPointMake(CGRectGetMidX(self.mapView.bounds), CGRectGetMidY(self.mapView.bounds)); - - srand48(0); - for (NSInteger iter = 0; iter < 10; iter++ ) { - - double zoom = (double)(drand48()*14.0); - - NSString *activityTitle = [NSString stringWithFormat:@"Zoom to %0.1f", zoom]; - [XCTContext runActivityNamed:activityTitle - block:^(id<XCTActivity> _Nonnull activity) { - MGLMapCamera *toCamera = [self.mapView cameraByZoomingToZoomLevel:zoom aroundAnchorPoint:anchor]; - [self internalTestSelecting:annotation withCamera:toCamera]; - }]; - } -} - -- (void)testSelectingAnnotationWhenMapIsScaledAndRotated { - - CLLocationCoordinate2D coordinates[] = { - { 0.005, 0.005 }, - { NAN, NAN } - }; - - NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates]; - MGLPointAnnotation *annotation = annotations.firstObject; - - srand48(0); - for (NSInteger iter = 0; iter < 10; iter++ ) { - - double zoom = (double)(7.0 + drand48()*7.0); - CLLocationDirection angle = (CLLocationDirection)((drand48()*1080.0) - 540.0); - - CGPoint anchor = CGPointMake(drand48()*CGRectGetWidth(self.mapView.bounds), drand48()*CGRectGetHeight(self.mapView.bounds)); - - NSString *activityTitle = [NSString stringWithFormat:@"Zoom to %0.1f", zoom]; - [XCTContext runActivityNamed:activityTitle - block:^(id<XCTActivity> _Nonnull activity) - { - mbgl::CameraOptions currentCameraOptions; - - currentCameraOptions.bearing = angle; - currentCameraOptions.anchor = mbgl::ScreenCoordinate { anchor.x, anchor.y }; - currentCameraOptions.zoom = zoom; - MGLMapCamera *toCamera = [self.mapView cameraForCameraOptions:currentCameraOptions]; - - [self internalTestSelecting:annotation withCamera:toCamera]; - }]; - } -} - - -- (void)testShowingAnnotationsThenSelectingAnimated { - [self internalTestShowingAnnotationsThenSelectingAnimated:YES]; -} - -- (void)testShowingAnnotationsThenSelecting { - [self internalTestShowingAnnotationsThenSelectingAnimated:NO]; -} - -- (void)internalTestShowingAnnotationsThenSelectingAnimated:(BOOL)animated { - srand48(0); - - CGFloat maxXPadding = std::max(CGRectGetWidth(self.mapView.bounds)/5.0, 100.0); - CGFloat maxYPadding = std::max(CGRectGetHeight(self.mapView.bounds)/5.0, 100.0); - - for (int i = 0; i < 10; i++) { - UIEdgeInsets edgePadding; - edgePadding.top = floor(drand48()*maxYPadding); - edgePadding.bottom = floor(drand48()*maxYPadding); - edgePadding.left = floor(drand48()*maxXPadding); - edgePadding.right = floor(drand48()*maxXPadding); - - UIEdgeInsets contentInsets; - contentInsets.top = floor(drand48()*maxYPadding); - contentInsets.bottom = floor(drand48()*maxYPadding); - contentInsets.left = floor(drand48()*maxXPadding); - contentInsets.right = floor(drand48()*maxXPadding); - - [self internalTestShowingAnnotationsThenSelectingAnimated:animated edgePadding:edgePadding contentInsets:contentInsets]; - } -} - -- (void)internalTestShowingAnnotationsThenSelectingAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgeInsets contentInsets:(UIEdgeInsets)contentInsets { - CLLocationCoordinate2D coordinates[21]; - - for (int i = 0; i < (int)(sizeof(coordinates)/sizeof(coordinates[0])); i++) - { - coordinates[i].latitude = drand48(); - coordinates[i].longitude = drand48(); - } - coordinates[20] = CLLocationCoordinate2DMake(NAN, NAN); - - NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates]; - - XCTestExpectation *showCompleted = [self expectationWithDescription:@"showCompleted"]; - - self.mapView.contentInset = contentInsets; - [self.mapView showAnnotations:annotations - edgePadding:edgeInsets - animated:animated - completionHandler:^{ - [showCompleted fulfill]; - }]; - - [self waitForExpectations:@[showCompleted] timeout:3.5]; - - // These tests will fail if this isn't here. But this isn't quite what we're - // seeing in https://github.com/mapbox/mapbox-gl-native/issues/15106 - [self waitForCollisionDetectionToRun]; - - for (MGLPointAnnotation *point in annotations) { - [self internalSelectDeselectAnnotation:point]; - } - - [self.mapView removeAnnotations:annotations]; - self.mapView.contentInset = UIEdgeInsetsZero; - [self waitForCollisionDetectionToRun]; -} - -- (NSArray*)internalAddAnnotationsAtCoordinates:(CLLocationCoordinate2D*)coordinates -{ - __block NSMutableArray *annotations = [NSMutableArray array]; - - [XCTContext runActivityNamed:@"Map setup" - block:^(id<XCTActivity> _Nonnull activity) - { - - NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer"; - - CGSize annotationSize = CGSizeMake(40.0, 40.0); - - self.viewForAnnotation = ^MGLAnnotationView*(MGLMapView *view, id<MGLAnnotation> annotation2) { - - if (![annotation2 isKindOfClass:[MGLPointAnnotation class]]) { - return nil; - } - - // No dequeue - MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation2 reuseIdentifier:MGLTestAnnotationReuseIdentifer]; - annotationView.bounds = (CGRect){ .origin = CGPointZero, .size = annotationSize }; - annotationView.backgroundColor = UIColor.redColor; - annotationView.enabled = YES; - - return annotationView; - }; - - CLLocationCoordinate2D *coordinatePtr = coordinates; - while (!isnan(coordinatePtr->latitude)) { - CLLocationCoordinate2D coordinate = *coordinatePtr++; - - MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init]; - annotation.title = NSStringFromSelector(_cmd); - annotation.coordinate = coordinate; - [annotations addObject:annotation]; - } - - [self.mapView addAnnotations:annotations]; - - }]; - - NSArray *copiedAnnotations = [annotations copy]; - annotations = nil; - - return copiedAnnotations; -} - -- (void)internalTestSelecting:(MGLPointAnnotation*)point withCamera:(MGLMapCamera*)camera { - - // Rotate - XCTestExpectation *rotationCompleted = [self expectationWithDescription:@"rotationCompleted"]; - [self.mapView setCamera:camera withDuration:0.1 animationTimingFunction:nil completionHandler:^{ - [rotationCompleted fulfill]; - }]; - - [self waitForExpectations:@[rotationCompleted] timeout:1.5]; - - // Collision detection may not have completed, if not we may not get our annotation. - [self waitForCollisionDetectionToRun]; - - // Look up annotation at point - [self internalSelectDeselectAnnotation:point]; -} - -- (void)internalSelectDeselectAnnotation:(MGLPointAnnotation*)point { - [XCTContext runActivityNamed:[NSString stringWithFormat:@"Select annotation: %@", point] - block:^(id<XCTActivity> _Nonnull activity) - { - CGPoint annotationPoint = [self.mapView convertCoordinate:point.coordinate toPointToView:self.mapView]; - - MGLAnnotationTag tagAtPoint = [self.mapView annotationTagAtPoint:annotationPoint persistingResults:YES]; - if (tagAtPoint != UINT32_MAX) - { - id <MGLAnnotation> annotation = [self.mapView annotationWithTag:tagAtPoint]; - XCTAssertNotNil(annotation); - - // Select - XCTestExpectation *selectionCompleted = [self expectationWithDescription:@"Selection completed"]; - [self.mapView selectAnnotation:annotation moveIntoView:NO animateSelection:NO completionHandler:^{ - [selectionCompleted fulfill]; - }]; - - [self waitForExpectations:@[selectionCompleted] timeout:0.05]; - - XCTAssert(self.mapView.selectedAnnotations.count == 1, @"There should only be 1 selected annotation"); - XCTAssertEqualObjects(self.mapView.selectedAnnotations.firstObject, annotation, @"The annotation should be selected"); - - // Deselect - [self.mapView deselectAnnotation:annotation animated:NO]; - } - else - { - XCTFail(@"Should be an annotation at this point: %@", NSStringFromCGPoint(annotationPoint)); - } - }]; - -} - -#pragma mark - Utilities - -- (void)runRunLoop { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; -} - -- (void)waitFor:(NSTimeInterval)seconds { - XCTestExpectation *timerExpired = [self expectationWithDescription:@"Timer expires"]; - - NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1 - target:self - selector:@selector(runRunLoop) - userInfo:nil - repeats:YES]; - - double duration = seconds * (double)NSEC_PER_SEC; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)duration), dispatch_get_main_queue(), ^{ - [timerExpired fulfill]; - }); - - [self waitForExpectations:@[timerExpired] timeout:seconds + 1.0]; - [timer invalidate]; -} - -- (void)waitForCollisionDetectionToRun { - XCTAssertNil(self.renderFinishedExpectation, @"Incorrect test setup"); - - [self.mapView setNeedsRerender]; - self.renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"]; - XCTestExpectation *timerExpired = [self expectationWithDescription:@"Timer expires"]; - - // Wait 1/2 second - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC >> 1)), dispatch_get_main_queue(), ^{ - [timerExpired fulfill]; - }); - - [self waitForExpectations:@[timerExpired, self.renderFinishedExpectation] timeout:5]; - - self.renderFinishedExpectation = nil; -} - -@end diff --git a/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm b/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm deleted file mode 100644 index 1527e8dbe5..0000000000 --- a/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm +++ /dev/null @@ -1,109 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" -#import "MGLTestUtility.h" -#import "../../darwin/src/MGLGeometry_Private.h" - -#include <mbgl/map/camera.hpp> - -@interface MGLCameraTransitionFinishTests : MGLMapViewIntegrationTest -@end - -@implementation MGLCameraTransitionFinishTests - -- (void)testEaseToCompletionHandler { - - MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0), - CLLocationCoordinate2DMake(1.0, 1.0)); - MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"]; - - [self.mapView setCamera:camera - withDuration:0.0 - animationTimingFunction:nil - completionHandler:^{ - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:0.5]; -} - -- (void)testEaseToCompletionHandlerAnimated { - - MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0), - CLLocationCoordinate2DMake(1.0, 1.0)); - MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"]; - - [self.mapView setCamera:camera - withDuration:0.3 - animationTimingFunction:nil - completionHandler:^{ - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:0.5]; -} - -- (void)testFlyToCompletionHandler { - - MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0), - CLLocationCoordinate2DMake(1.0, 1.0)); - MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"]; - - [self.mapView flyToCamera:camera - withDuration:0.0 - completionHandler:^{ - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:0.5]; -} - -- (void)testFlyToCompletionHandlerAnimated { - - MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0), - CLLocationCoordinate2DMake(1.0, 1.0)); - MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"]; - - [self.mapView flyToCamera:camera - withDuration:0.3 - completionHandler:^{ - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:0.5]; -} -@end - -#pragma mark - camera transitions with NaN values - -@interface MGLMapView (MGLCameraTransitionFinishNaNTests) -- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets; -@end - -@interface MGLCameraTransitionNaNZoomMapView: MGLMapView -@end - -@implementation MGLCameraTransitionNaNZoomMapView -- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets { - mbgl::CameraOptions options = [super cameraOptionsObjectForAnimatingToCamera:camera edgePadding:insets]; - options.zoom = NAN; - return options; -} -@end - -// Subclass the entire test suite, but with a different MGLMapView subclass -@interface MGLCameraTransitionFinishNaNTests : MGLCameraTransitionFinishTests -@end - -@implementation MGLCameraTransitionFinishNaNTests -- (MGLMapView *)mapViewForTestWithFrame:(CGRect)rect styleURL:(NSURL *)styleURL { - return [[MGLCameraTransitionNaNZoomMapView alloc] initWithFrame:rect styleURL:styleURL]; -} -@end - diff --git a/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionTests.mm b/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionTests.mm deleted file mode 100644 index 27ab7964c1..0000000000 --- a/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionTests.mm +++ /dev/null @@ -1,394 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" -#import "MGLTestUtility.h" -#import "../../darwin/src/MGLGeometry_Private.h" - -@interface MGLCameraTransitionTests : MGLMapViewIntegrationTest -@end - -@implementation MGLCameraTransitionTests - -- (void)testSetAndResetNorthWithDispatchAsyncInDelegateMethod { - - XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"]; - expectation.expectedFulfillmentCount = 2; - expectation.assertForOverFulfill = YES; - - __weak typeof(self) weakself = self; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - MGLCameraTransitionTests *strongSelf = weakself; - - if (!strongSelf) return; - - [expectation fulfill]; - - MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading); - 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 typeof(self) weakself = self; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - MGLCameraTransitionTests *strongSelf = weakself; - - if (!strongSelf) return; - - [expectation fulfill]; - - MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading); - 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 typeof(self) weakself = self; - __block BOOL startedReset = NO; - __block BOOL finishedReset = NO; - - self.regionIsChanging = ^(MGLMapView *mapView) { - MGLCameraTransitionTests *strongSelf = weakself; - if (!strongSelf) return; - - if (!startedReset) { - NSLog(@"Reset to north, interrupting the previous transition"); - startedReset = YES; - [mapView resetNorth]; - finishedReset = YES; - } - }; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - MGLCameraTransitionTests *strongSelf = weakself; - if (!strongSelf) return; - - MGLTestAssert(strongSelf, startedReset); - - if (finishedReset) { - MGLTestAssert(strongSelf, !(reason & MGLCameraChangeReasonTransitionCancelled)); - [expectation fulfill]; - } - else { - MGLTestAssert(strongSelf, reason & MGLCameraChangeReasonTransitionCancelled); - } - }; - - [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 typeof(self) weakself = self; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.15 * NSEC_PER_SEC), - dispatch_get_main_queue(), - ^{ - MGLCameraTransitionTests *strongSelf = weakself; - - [strongSelf.mapView setCenterCoordinate:dc zoomLevel:zoomLevel animated:NO]; - MGLTestAssertEqualWithAccuracy(strongSelf, - dc.latitude, - strongSelf.mapView.centerCoordinate.latitude, - 0.0005, - @"setting center coordinate should cancel transitions"); - MGLTestAssertEqualWithAccuracy(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 typeof(self) weakself = self; - __block NSInteger delegateCallCount = 0; - - CLLocationCoordinate2D target = CLLocationCoordinate2DMake(40.0, 40.0); - CLLocationCoordinate2D target2 = CLLocationCoordinate2DMake(-40.0, -40.0); - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - MGLCameraTransitionTests *strongSelf = weakself; - - if (!strongSelf) return; - - MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading); - - CLLocationCoordinate2D center = mapView.centerCoordinate; - - switch(delegateCallCount) { - case 0: - { - // Our center coordinate should match our target (assuming we're not - // constrained by zoom level) - MGLTestAssertEqualWithAccuracy(strongSelf, - target.longitude, - center.longitude, - 0.0005, - @"center coordinate longitude should be at target"); - - MGLTestAssertEqualWithAccuracy(strongSelf, - target.latitude, - center.latitude, - 0.0005, - @"center coordinate latitude should be at target"); - - // Now set another coordinate. - // Should take MGLAnimationDuration 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) - MGLTestAssertEqualWithAccuracy(strongSelf, - target2.longitude, - center.longitude, - 0.0005, - @"center coordinate longitude should be at target2"); - - MGLTestAssertEqualWithAccuracy(strongSelf, - target2.latitude, - center.latitude, - 0.0005, - @"center coordinate latitude should be at target2"); - break; - - } - - default: - MGLTestFail(strongSelf); - break; - } - - delegateCallCount++; - - [expectation fulfill]; - }; - - // Should take MGLAnimationDuration 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 typeof(self) 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 = MGLAltitudeForZoomLevel(zoomLevel, 0.0, target.latitude, self.mapView.frame.size); - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - MGLCameraTransitionTests *strongSelf = weakself; - - if (!strongSelf) return; - - MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading); - - 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) - MGLTestAssertEqualWithAccuracy(strongSelf, - target.longitude, - center.longitude, - 0.0005, - @"center coordinate longitude should be at target"); - - MGLTestAssertEqualWithAccuracy(strongSelf, - target.latitude, - center.latitude, - 0.0005, - @"center coordinate latitude should be at target"); - - // Now set another coordinate. - MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:target2 - altitude:altitude - pitch:0.0 - heading:0.0]; - - // flyToCamera can take a while... - [mapView flyToCamera:camera completionHandler:^{ - MGLTestAssert(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) - MGLTestAssertEqualWithAccuracy(strongSelf, - target2.longitude, - center.longitude, - 0.0005, - @"center coordinate longitude should be at target2"); - - MGLTestAssertEqualWithAccuracy(strongSelf, - target2.latitude, - center.latitude, - 0.0005, - @"center coordinate latitude should be at target2"); - - runloop = NO; - break; - } - - default: - MGLTestFail(strongSelf); - break; - } - - delegateCallCount++; - - [expectation fulfill]; - }; - - // Should take MGLAnimationDuration - [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 -} - -#pragma mark - Pending tests - -- (void)testContinuallyResettingNorthInIsChanging🙁{ - // 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 = ^(MGLMapView *mapView) { - [mapView resetNorth]; - }; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason 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)testContinuallySettingCoordinateInIsChanging🙁 { - // See above comment in `-testContinuallyResettingNorthInIsChanging🙁` - - // 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 typeof(self) weakself = self; - - self.regionIsChanging = ^(MGLMapView *mapView) { - [weakself.mapView setCenterCoordinate:CLLocationCoordinate2DMake(-40.0, -40.0) animated:YES]; - }; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason 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 diff --git a/platform/ios/Integration Tests/Info.plist b/platform/ios/Integration Tests/Info.plist deleted file mode 100644 index 6c40a6cd0c..0000000000 --- a/platform/ios/Integration Tests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>$(DEVELOPMENT_LANGUAGE)</string> - <key>CFBundleExecutable</key> - <string>$(EXECUTABLE_NAME)</string> - <key>CFBundleIdentifier</key> - <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleName</key> - <string>$(PRODUCT_NAME)</string> - <key>CFBundlePackageType</key> - <string>BNDL</string> - <key>CFBundleShortVersionString</key> - <string>1.0</string> - <key>CFBundleVersion</key> - <string>1</string> -</dict> -</plist> diff --git a/platform/ios/Integration Tests/MBGLIntegrationTests.mm b/platform/ios/Integration Tests/MBGLIntegrationTests.mm deleted file mode 100644 index d0f5f6a79d..0000000000 --- a/platform/ios/Integration Tests/MBGLIntegrationTests.mm +++ /dev/null @@ -1,252 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" -#import "MGLMapView_Private.h" -#import "MGLMapView+Impl.h" - -#include <mbgl/gfx/renderable.hpp> - -@interface MBGLIntegrationTests : MGLMapViewIntegrationTest -@end - -@implementation MBGLIntegrationTests - -#pragma mark - Tests - -- (void)waitForMapViewToBeRendered { - [self waitForMapViewToBeRenderedWithTimeout:10]; -} - -// This test does not strictly need to be in this test file/target. Including here for convenience. -- (void)testOpenGLLayerDoesNotLeakWhenCreatedAndDestroyedWithoutAddingToStyle { - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - __weak id weakLayer = layer; - layer = nil; - - XCTAssertNil(weakLayer); -} - -- (void)testAddingRemovingOpenGLLayerWithoutRendering { - XCTAssertNotNil(self.style); - - void(^addRemoveGLLayer)(void) = ^{ - __weak id weakLayer = nil; - - @autoreleasepool { - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - [self.style insertLayer:layer atIndex:0]; - weakLayer = layer; - - // Nil the layer prior to remove to ensure it's being retained - layer = nil; - [self.style removeLayer:weakLayer]; - } - - XCTAssertNil(weakLayer); - }; - - addRemoveGLLayer(); - addRemoveGLLayer(); - addRemoveGLLayer(); -} - -- (void)testReusingOpenGLLayerIdentifier { - __weak MGLOpenGLStyleLayer *weakLayer2; - - @autoreleasepool { - MGLOpenGLStyleLayer *layer1 = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - [self.style insertLayer:layer1 atIndex:0]; - [self waitForMapViewToBeRendered]; - [self.style removeLayer:layer1]; - - MGLOpenGLStyleLayer *layer2 = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - weakLayer2 = layer2; - - XCTAssertNotNil(layer2); - XCTAssert(layer1 != layer2); - - [self.style insertLayer:layer2 atIndex:0]; - [self waitForMapViewToBeRendered]; - [self.style removeLayer:layer2]; - - XCTAssertNil([layer1 style]); - XCTAssertNil([layer2 style]); - } - - // At this point, layer2 (and layer1) should still be around, - // since the render process needs to keep a reference to them. - XCTAssertNotNil(weakLayer2); - - // Let render loop run enough to release the layers - [self waitForMapViewToBeRendered]; - XCTAssertNil(weakLayer2); -} - -- (void)testAddingRemovingOpenGLLayer { - XCTAssertNotNil(self.style); - - void(^addRemoveGLLayer)(void) = ^{ - - __weak id retrievedLayer = nil; - - @autoreleasepool { - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - [self.style insertLayer:layer atIndex:0]; - layer = nil; - - [self waitForMapViewToBeRendered]; - - retrievedLayer = [self.style layerWithIdentifier:@"gl-layer"]; - XCTAssertNotNil(retrievedLayer); - - [self.style removeLayer:retrievedLayer]; - [self waitForMapViewToBeRendered]; - } - - XCTAssertNil(retrievedLayer); - }; - - addRemoveGLLayer(); - addRemoveGLLayer(); - addRemoveGLLayer(); -} - -- (void)testReusingOpenGLLayer { - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - [self.style insertLayer:layer atIndex:0]; - [self waitForMapViewToBeRendered]; - - [self.style removeLayer:layer]; - [self waitForMapViewToBeRendered]; - - [self.style insertLayer:layer atIndex:0]; - [self waitForMapViewToBeRendered]; - - [self.style removeLayer:layer]; - [self waitForMapViewToBeRendered]; -} - -- (void)testOpenGLLayerDoesNotLeakWhenRemovedFromStyle { - __weak id weakLayer; - @autoreleasepool { - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - weakLayer = layer; - [self.style insertLayer:layer atIndex:0]; - layer = nil; - - [self waitForMapViewToBeRendered]; - [self.style removeLayer:[self.style layerWithIdentifier:@"gl-layer"]]; - } - - MGLStyleLayer *layer2 = weakLayer; - - XCTAssertNotNil(weakLayer); - [self waitForMapViewToBeRendered]; - - layer2 = nil; - XCTAssertNil(weakLayer); -} - -- (void)testOpenGLLayerDoesNotLeakWhenStyleChanged { - __weak MGLOpenGLStyleLayer *weakLayer; - - @autoreleasepool { - { - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - weakLayer = layer; - [self.style insertLayer:layer atIndex:0]; - layer = nil; - } - } - - XCTAssertNotNil(weakLayer); - - [self waitForMapViewToBeRendered]; - - MGLStyleLayer *layer2 = [self.mapView.style layerWithIdentifier:@"gl-layer"]; - - NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; - self.styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; - [self.mapView setStyleURL:styleURL]; - [self waitForExpectations:@[self.styleLoadingExpectation] timeout:10]; - - // At this point the C++ CustomLayer will have been destroyed, and the rawLayer pointer has been NULLed - XCTAssert(weakLayer == layer2); - XCTAssertNotNil(weakLayer); - - // Asking the style for the layer should return nil - MGLStyleLayer *layer3 = [self.mapView.style layerWithIdentifier:@"gl-layer"]; - XCTAssertNil(layer3); -} - - -- (void)testOpenGLLayerDoesNotLeakWhenMapViewDeallocs { - __weak id weakLayer; - - @autoreleasepool { - - NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; - MGLMapView *mapView2 = [[MGLMapView alloc] initWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL]; - mapView2.delegate = self; - - XCTAssertNil(mapView2.style); - - self.styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; - [self waitForExpectationsWithTimeout:10 handler:nil]; - - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - weakLayer = layer; - [mapView2.style insertLayer:layer atIndex:0]; - layer = nil; - - [self waitForMapViewToBeRendered]; - } - XCTAssertNil(weakLayer); -} - -- (void)testMGLMapViewImplHasCorrectSize { - NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; - self.styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; - [self.mapView setStyleURL:styleURL]; - [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(9.6315313, 52.4133574) animated:NO]; - [self waitForExpectations:@[self.styleLoadingExpectation] timeout:1]; - - MGLMapViewImpl *mapViewImpl = [self.mapView viewImpl]; - CGFloat scaleFactor = [UIScreen mainScreen].scale; - mbgl::Size renderableSize = mapViewImpl->getRendererBackend().getDefaultRenderable().getSize(); - mbgl::Size viewSize = { - static_cast<uint32_t>(self.mapView.bounds.size.width * scaleFactor), - static_cast<uint32_t>(self.mapView.bounds.size.height * scaleFactor) - }; - - // Test that mapView and default renderable have the same size. - XCTAssertTrue(renderableSize == viewSize); - - CLLocationCoordinate2D coordinates[] = { - CLLocationCoordinate2DMake(9.6315313, 52.4133574), - CLLocationCoordinate2DMake(24.9410248, 60.1733244)}; - - MGLPointCollectionFeature *points = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0])]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"heatmap" shape:points options:nil]; - [self.style addSource:source]; - - MGLHeatmapStyleLayer *heatmapLayer = [[MGLHeatmapStyleLayer alloc] initWithIdentifier:@"lineLayer" source:source]; - [self.style addLayer:heatmapLayer]; - - // Test that heatmap layer can create a texture and be successfully rendered. - [self waitForMapViewToBeRendered]; - - // Resize frame of the view. - [self.mapView setFrame: CGRect{self.mapView.bounds.origin, {256, 256}}]; - - // Force sync re-layout. - [self.mapView layoutIfNeeded]; - - // Test that mapView and default renderable have the same size after re-layout. - renderableSize = mapViewImpl->getRendererBackend().getDefaultRenderable().getSize(); - viewSize = { static_cast<uint32_t>(self.mapView.bounds.size.width * scaleFactor), - static_cast<uint32_t>(self.mapView.bounds.size.height * scaleFactor) }; - XCTAssertTrue(renderableSize == viewSize); - [self waitForMapViewToBeRendered]; -} - -@end - diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h deleted file mode 100644 index 08576e884a..0000000000 --- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h +++ /dev/null @@ -1,45 +0,0 @@ -#import <XCTest/XCTest.h> -#import <Mapbox/Mapbox.h> -#import "MGLTestUtility.h" - -#define MGLTestFail(myself, ...) \ - _XCTPrimitiveFail(myself, __VA_ARGS__) - -#define MGLTestAssert(myself, expression, ...) \ - _XCTPrimitiveAssertTrue(myself, expression, @#expression, __VA_ARGS__) - -#define MGLTestAssertEqualWithAccuracy(myself, expression1, expression2, accuracy, ...) \ - _XCTPrimitiveAssertEqualWithAccuracy(myself, expression1, @#expression1, expression2, @#expression2, accuracy, @#accuracy, __VA_ARGS__) -#define MGLTestAssertNil(myself, expression, ...) \ - _XCTPrimitiveAssertNil(myself, expression, @#expression, __VA_ARGS__) - -#define MGLTestAssertNotNil(myself, expression, ...) \ - _XCTPrimitiveAssertNotNil(myself, expression, @#expression, __VA_ARGS__) - -#define MGLTestWarning(expression, format, ...) \ -({ \ - if (!(expression)) { \ - NSString *message = [NSString stringWithFormat:format, ##__VA_ARGS__]; \ - printf("warning: Test Case '%s' at line %d: '%s' %s\n", __PRETTY_FUNCTION__, __LINE__, #expression, message.UTF8String); \ - } \ -}) - -@interface MGLMapViewIntegrationTest : XCTestCase <MGLMapViewDelegate> -@property (nonatomic) MGLMapView *mapView; -@property (nonatomic) UIWindow *window; -@property (nonatomic) MGLStyle *style; -@property (nonatomic) XCTestExpectation *styleLoadingExpectation; -@property (nonatomic) XCTestExpectation *renderFinishedExpectation; -@property (nonatomic) MGLAnnotationView * (^viewForAnnotation)(MGLMapView *mapView, id<MGLAnnotation> annotation); -@property (nonatomic) void (^regionWillChange)(MGLMapView *mapView, BOOL animated); -@property (nonatomic) void (^regionIsChanging)(MGLMapView *mapView); -@property (nonatomic) void (^regionDidChange)(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated); -@property (nonatomic) CGPoint (^mapViewUserLocationAnchorPoint)(MGLMapView *mapView); -@property (nonatomic) BOOL (^mapViewAnnotationCanShowCalloutForAnnotation)(MGLMapView *mapView, id<MGLAnnotation> annotation); -@property (nonatomic) id<MGLCalloutView> (^mapViewCalloutViewForAnnotation)(MGLMapView *mapView, id<MGLAnnotation> annotation); - -// Utility methods -- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout; -- (void)waitForMapViewToBeRenderedWithTimeout:(NSTimeInterval)timeout; -- (MGLMapView *)mapViewForTestWithFrame:(CGRect)rect styleURL:(NSURL *)styleURL; -@end diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m deleted file mode 100644 index 4095b4620b..0000000000 --- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m +++ /dev/null @@ -1,200 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" - -@interface MGLMapView (MGLMapViewIntegrationTest) -- (void)updateFromDisplayLink:(CADisplayLink *)displayLink; -- (void)setNeedsRerender; -@end - -@implementation MGLMapViewIntegrationTest - -+ (XCTestSuite*)defaultTestSuite { - - XCTestSuite *defaultTestSuite = [super defaultTestSuite]; - - NSArray *tests = defaultTestSuite.tests; - - XCTestSuite *newTestSuite = [XCTestSuite testSuiteWithName:defaultTestSuite.name]; - - BOOL runPendingTests = [[[NSProcessInfo processInfo] environment][@"MAPBOX_RUN_PENDING_TESTS"] boolValue]; - NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; - - for (XCTest *test in tests) { - - // Check for pending tests - if ([test.name containsString:@"PENDING"] || - [test.name containsString:@"🙁"]) { - if (!runPendingTests) { - printf("warning: '%s' is a pending test - skipping\n", test.name.UTF8String); - continue; - } - } - - // Check for tests that require a valid access token - if ([test.name containsString:@"🔒"]) { - if (!accessToken) { - printf("warning: MAPBOX_ACCESS_TOKEN env var is required for test '%s' - skipping.\n", test.name.UTF8String); - continue; - } - } - - [newTestSuite addTest:test]; - } - - return newTestSuite; -} - -- (MGLMapView *)mapViewForTestWithFrame:(CGRect)rect styleURL:(NSURL *)styleURL { - return [[MGLMapView alloc] initWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL]; -} - -- (void)setUp { - [super setUp]; - - NSString *accessToken; - - if ([self.name containsString:@"🔒"]) { - accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; - - if (!accessToken) { - printf("warning: MAPBOX_ACCESS_TOKEN env var is required for test '%s' - trying anyway.\n", self.name.UTF8String); - } - } - - [MGLAccountManager setAccessToken:accessToken ?: @"pk.feedcafedeadbeefbadebede"]; - - NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; - - self.mapView = [self mapViewForTestWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL]; - self.mapView.delegate = self; - - UIView *superView = [[UIView alloc] initWithFrame:UIScreen.mainScreen.bounds]; - [superView addSubview:self.mapView]; - self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; - [self.window addSubview:superView]; - [self.window makeKeyAndVisible]; - - if (!self.mapView.style) { - [self waitForMapViewToFinishLoadingStyleWithTimeout:10]; - } -} - -- (void)tearDown { - self.styleLoadingExpectation = nil; - self.renderFinishedExpectation = nil; - self.mapView = nil; - self.style = nil; - self.window = nil; - [MGLAccountManager setAccessToken:nil]; - - [super tearDown]; -} - -#pragma mark - MGLMapViewDelegate - -- (MGLAnnotationView*)mapView:(MGLMapView *)mapView viewForAnnotation:(id<MGLAnnotation>)annotation { - if (self.viewForAnnotation) { - return self.viewForAnnotation(mapView, annotation); - } - - return nil; -} - -- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { - XCTAssertNotNil(mapView.style); - XCTAssertEqual(mapView.style, style); - - [self.styleLoadingExpectation fulfill]; -} - -- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(__unused BOOL)fullyRendered { - [self.renderFinishedExpectation fulfill]; - self.renderFinishedExpectation = nil; -} - -- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated { - if (self.regionWillChange) { - self.regionWillChange(mapView, animated); - } -} - -- (void)mapViewRegionIsChanging:(MGLMapView *)mapView { - if (self.regionIsChanging) { - self.regionIsChanging(mapView); - } -} - -- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated { - if (self.regionDidChange) { - self.regionDidChange(mapView, reason, animated); - } -} - -- (CGPoint)mapViewUserLocationAnchorPoint:(MGLMapView *)mapView { - if (self.mapViewUserLocationAnchorPoint) { - return self.mapViewUserLocationAnchorPoint(mapView); - } - return CGPointZero; -} - -- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id<MGLAnnotation>)annotation { - if (self.mapViewAnnotationCanShowCalloutForAnnotation) { - return self.mapViewAnnotationCanShowCalloutForAnnotation(mapView, annotation); - } - return NO; -} - -- (id<MGLCalloutView>)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id<MGLAnnotation>)annotation { - if (self.mapViewCalloutViewForAnnotation) { - return self.mapViewCalloutViewForAnnotation(mapView, annotation); - } - return nil; -} - -#pragma mark - Utilities - -- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout { - XCTAssertNil(self.styleLoadingExpectation); - self.styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; - [self waitForExpectations:@[self.styleLoadingExpectation] timeout:timeout]; - self.styleLoadingExpectation = nil; -} - -- (void)waitForMapViewToBeRenderedWithTimeout:(NSTimeInterval)timeout { - XCTAssertNil(self.renderFinishedExpectation); - [self.mapView setNeedsRerender]; - self.renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"]; - [self waitForExpectations:@[self.renderFinishedExpectation] timeout:timeout]; - self.renderFinishedExpectation = nil; -} - -- (void)waitForExpectations:(NSArray<XCTestExpectation *> *)expectations timeout:(NSTimeInterval)seconds { - - NSTimer *timer; - - if (@available(iOS 10.0, *)) { - // We're good. - } - else if (self.mapView) { - // Before iOS 10 it seems that the display link is not called during the - // waitForExpectations below - - timer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 - target:self - selector:@selector(updateMapViewDisplayLinkFromTimer:) - userInfo:nil - repeats:YES]; - } - - [super waitForExpectations:expectations timeout:seconds]; - [timer invalidate]; -} - -- (void)updateMapViewDisplayLinkFromTimer:(NSTimer *)timer { - [self.mapView updateFromDisplayLink:nil]; -} - -- (MGLStyle *)style { - return self.mapView.style; -} - -@end diff --git a/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m b/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m deleted file mode 100644 index c7925d7896..0000000000 --- a/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m +++ /dev/null @@ -1,366 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" -#import "MGLTestUtility.h" - -@interface MGLMapView (MGLMapViewPendingBlockTests) -@property (nonatomic) NSMutableArray *pendingCompletionBlocks; -- (void)pauseRendering:(__unused NSNotification *)notification; -@end - -@interface MGLMapViewPendingBlockTests : MGLMapViewIntegrationTest -@property (nonatomic, copy) void (^observation)(NSDictionary*); -@property (nonatomic) BOOL completionHandlerCalled; -@end - -@implementation MGLMapViewPendingBlockTests - -- (void)testSetCenterCoordinate { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) - zoomLevel:10.0 - direction:0 - animated:NO - completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testSetCenterCoordinateAnimated { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) - zoomLevel:10.0 - direction:0 - animated:YES - completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testSetVisibleCoordinateBounds { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1)); - [strongSelf.mapView setVisibleCoordinateBounds:unitBounds - edgePadding:UIEdgeInsetsZero - animated:NO - completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testSetVisibleCoordinateBoundsAnimated { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1)); - [strongSelf.mapView setVisibleCoordinateBounds:unitBounds - edgePadding:UIEdgeInsetsZero - animated:YES - completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testSetCamera { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1)); - MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds]; - - [strongSelf.mapView setCamera:camera withDuration:0.0 animationTimingFunction:nil completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testSetCameraAnimated { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1)); - MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds]; - - [strongSelf.mapView setCamera:camera withDuration:0.3 animationTimingFunction:nil completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testFlyToCamera { - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1)); - MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds]; - - [strongSelf.mapView flyToCamera:camera withDuration:0.0 completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - -- (void)testFlyToCameraAnimated { - - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1)); - MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds]; - - [strongSelf.mapView flyToCamera:camera withDuration:0.3 completionHandler:completion]; - } - else { - completion(); - } - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:nil]; -} - - -#pragma mark - test interrupting regular rendering - -- (void)testSetCenterCoordinateSetHidden { - - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) - zoomLevel:10.0 - direction:0 - animated:NO - completionHandler:completion]; - } - else { - completion(); - } - }; - - dispatch_block_t addedToPending = ^{ - __typeof__(self) strongSelf = weakSelf; - - MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled); - - // Now hide the mapview - strongSelf.mapView.hidden = YES; - - MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled); - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:addedToPending]; -} - -- (void)testSetCenterCoordinatePauseRendering { - - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) - zoomLevel:10.0 - direction:0 - animated:NO - completionHandler:completion]; - } - else { - completion(); - } - }; - - dispatch_block_t addedToPending = ^{ - __typeof__(self) strongSelf = weakSelf; - - MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled); - - // Pause rendering, stopping display link - [strongSelf.mapView pauseRendering:nil]; - - MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled); - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:addedToPending]; -} - -- (void)testSetCenterCoordinateRemoveFromSuperview { - - __typeof__(self) weakSelf = self; - - void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) { - __typeof__(self) strongSelf = weakSelf; - - if (strongSelf) { - [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) - zoomLevel:10.0 - direction:0 - animated:NO - completionHandler:completion]; - } - else { - completion(); - } - }; - - dispatch_block_t addedToPending = ^{ - __typeof__(self) strongSelf = weakSelf; - - MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled); - - // Remove from window, triggering validateDisplayLink - [strongSelf.mapView removeFromSuperview]; - - MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled); - }; - - [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd) - transition:transition - addToPendingCallback:addedToPending]; -} - -#pragma mark - Shared utility methods - -- (void)internalTestCompletionBlockAddedToPendingForTestName:(NSString *)testName - transition:(void (^)(dispatch_block_t))transition - addToPendingCallback:(dispatch_block_t)addToPendingCallback { - - XCTestExpectation *expectation = [self expectationWithDescription:testName]; - - __weak __typeof__(self) myself = self; - - dispatch_block_t block = ^{ - myself.completionHandlerCalled = YES; - [expectation fulfill]; - }; - - XCTAssertNotNil(transition); - transition(block); - - XCTAssert(!self.completionHandlerCalled); - XCTAssert(self.mapView.pendingCompletionBlocks.count == 0); - - __block BOOL blockAddedToPendingBlocks = NO; - - // Observes changes to pendingCompletionBlocks (including additions) - self.observation = ^(NSDictionary *change){ - - NSLog(@"change = %@ count = %lu", change, myself.mapView.pendingCompletionBlocks.count); - - NSArray *value = change[NSKeyValueChangeNewKey]; - - MGLTestAssert(myself, [value isKindOfClass:[NSArray class]]); - - if (value.count > 0) { - MGLTestAssert(myself, [value containsObject:block]); - MGLTestAssert(myself, !blockAddedToPendingBlocks); - if ([myself.mapView.pendingCompletionBlocks containsObject:block]) { - blockAddedToPendingBlocks = YES; - - if (addToPendingCallback) { - addToPendingCallback(); - } - } - } - }; - - [self.mapView addObserver:self forKeyPath:@"pendingCompletionBlocks" options:NSKeyValueObservingOptionNew context:_cmd]; - - [self waitForExpectations:@[expectation] timeout:0.5]; - - XCTAssert(blockAddedToPendingBlocks); - XCTAssert(self.completionHandlerCalled); - XCTAssert(self.mapView.pendingCompletionBlocks.count == 0); - - [self.mapView removeObserver:self forKeyPath:@"pendingCompletionBlocks" context:_cmd]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { - if (self.observation) { - self.observation(change); - } -} -@end diff --git a/platform/ios/Integration Tests/MGLShapeSourceTests.m b/platform/ios/Integration Tests/MGLShapeSourceTests.m deleted file mode 100644 index 836118450e..0000000000 --- a/platform/ios/Integration Tests/MGLShapeSourceTests.m +++ /dev/null @@ -1,163 +0,0 @@ -// -// MBShapeSourceTests.m -// integration -// -// Created by Julian Rex on 4/5/18. -// Copyright © 2018 Mapbox. All rights reserved. -// - -#import "MGLMapViewIntegrationTest.h" - -@interface MGLShapeSourceTests : MGLMapViewIntegrationTest -@end - -@implementation MGLShapeSourceTests - -- (void)testSettingShapeSourceToNilInRegionDidChange { - - NSMutableArray *features = [[NSMutableArray alloc] init]; - - for (NSUInteger i = 0; i <= 180; i+=5) { - CLLocationCoordinate2D coord[4] = { - CLLocationCoordinate2DMake(round(0), round(i)), - CLLocationCoordinate2DMake(round(20), round(i)), - CLLocationCoordinate2DMake(round(0), round(i / 2 )), - CLLocationCoordinate2DMake(round(20), round(i / 2))}; - - MGLPolygonFeature *feature = [MGLPolygonFeature polygonWithCoordinates:coord count:4]; - [features addObject:feature]; - } - - MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"source" features:features options:nil]; - [self.style addSource:shapeSource]; - - MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layer" source:shapeSource]; - layer.fillOpacity = [NSExpression expressionForConstantValue:@0.5]; - [self.style addLayer:layer]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"]; - expectation.expectedFulfillmentCount = 1; - expectation.assertForOverFulfill = YES; - - __weak typeof(self) weakself = self; - __block NSInteger delegateCallCount = 0; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - MGLShapeSourceTests *strongSelf = weakself; - - if (!strongSelf) - return; - - delegateCallCount++; - - // Setting the shapeSource.shape = nil, was causing an infinite loop, so here - // we check for a runaway call. 10 here is arbitrary. We could argue that this - // should check that the call count is only 1, however in this case we particularly - // want to check for the infinite loop. - // See https://github.com/mapbox/mapbox-gl-native/issues/11180 - - if (delegateCallCount > 10) { - MGLTestFail(strongSelf); - } - else { - shapeSource.shape = nil; - } - - [expectation fulfill]; - }; - - // setCenterCoordinate is NOT animated here. - [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)]; - [self waitForExpectations:@[expectation] timeout:5.0]; -} - -- (void)testSettingShapeSourceToNilInRegionIsChanging { - - NSMutableArray *features = [[NSMutableArray alloc] init]; - - for (NSUInteger i = 0; i <= 180; i+=5) { - CLLocationCoordinate2D coord[4] = { - CLLocationCoordinate2DMake(round(0), round(i)), - CLLocationCoordinate2DMake(round(20), round(i)), - CLLocationCoordinate2DMake(round(0), round(i / 2 )), - CLLocationCoordinate2DMake(round(20), round(i / 2))}; - - MGLPolygonFeature *feature = [MGLPolygonFeature polygonWithCoordinates:coord count:4]; - [features addObject:feature]; - } - - MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"source" features:features options:nil]; - [self.style addSource:shapeSource]; - - MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layer" source:shapeSource]; - layer.fillOpacity = [NSExpression expressionForConstantValue:@0.5]; - [self.style addLayer:layer]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"]; - expectation.expectedFulfillmentCount = 1; - expectation.assertForOverFulfill = YES; - - __block NSInteger delegateCallCount = 0; - __weak typeof(self) weakself = self; - - self.regionIsChanging = ^(MGLMapView *mapView) { - // See https://github.com/mapbox/mapbox-gl-native/issues/11180 - shapeSource.shape = nil; - }; - - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - delegateCallCount++; - - if (delegateCallCount > 1) { - MGLTestFail(weakself); - } - - [expectation fulfill]; - }; - - // Should take MGLAnimationDuration seconds (0.3) - [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) animated:YES]; - [self waitForExpectations:@[expectation] timeout:1.0]; -} - -- (void)testShapeSourceWithLineDistanceMetrics { - CLLocationCoordinate2D coordinates[] = { - CLLocationCoordinate2DMake(9.6315313, 52.4133574), - CLLocationCoordinate2DMake(24.9410248, 60.1733244)}; - - MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0])]; - NSDictionary *options = @{MGLShapeSourceOptionLineDistanceMetrics: @YES}; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"route" shape:polylineFeature options:options]; - MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayer" source:source]; - - [self.style addSource:source]; - [self.style addLayer:lineLayer]; - [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(9.6315313, 52.4133574) animated:YES]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"]; - expectation.expectedFulfillmentCount = 1; - expectation.assertForOverFulfill = YES; - - __weak id weakself = self; - self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) { - - id strongSelf = weakself; - if (!strongSelf) - return; - - NSArray *features = [source featuresMatchingPredicate:nil]; - MGLTestAssert(strongSelf, features.count == 1UL, @"Should contain one Feature"); - - MGLPolylineFeature *feature = [features objectAtIndex:0]; - MGLTestAssertNotNil(strongSelf, [feature.attributes objectForKey:@"mapbox_clip_start"], @"Attributes should contain mapbox_clip_start property"); - MGLTestAssertNotNil(strongSelf, [feature.attributes objectForKey:@"mapbox_clip_end"], @"Attributes should contain mapbox_clip_end property"); - - [expectation fulfill]; - }; - - [self waitForExpectations:@[expectation] timeout:1.0]; -} - -@end diff --git a/platform/ios/Integration Tests/MGLSourceTests.swift b/platform/ios/Integration Tests/MGLSourceTests.swift deleted file mode 100644 index 69fa0182b5..0000000000 --- a/platform/ios/Integration Tests/MGLSourceTests.swift +++ /dev/null @@ -1,45 +0,0 @@ -import XCTest - -class MGLSourceTests: MGLMapViewIntegrationTest { - - // See testForRaisingExceptionsOnStaleStyleObjects for Obj-C sibling. - func testForRaisingExceptionsOnStaleStyleObjectsOnRemoveFromMapView() { - - guard - let configURL = URL(string: "mapbox://examples.2uf7qges") else { - XCTFail() - return - } - - let source = MGLVectorTileSource(identifier: "trees", configurationURL: configURL) - mapView.style?.addSource(source) - - let bundle = Bundle(for: type(of: self)) - - guard let styleURL = bundle.url(forResource: "one-liner", withExtension: "json") else { - XCTFail() - return - } - - styleLoadingExpectation = nil; - - mapView.centerCoordinate = CLLocationCoordinate2D(latitude : 38.897, longitude : -77.039) - mapView.zoomLevel = 10.5 - mapView.styleURL = styleURL - - waitForMapViewToFinishLoadingStyle(withTimeout: 10.0) - - let expect = expectation(description: "Remove source should error") - - do { - try mapView.style?.removeSource(source, error: ()) - } - catch let error as NSError { - XCTAssertEqual(error.domain, MGLErrorDomain) - XCTAssertEqual(error.code, MGLErrorCode.sourceCannotBeRemovedFromStyle.rawValue) - expect.fulfill() - } - - wait(for: [expect], timeout: 0.1) - } -} diff --git a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m deleted file mode 100644 index f5f2f957d3..0000000000 --- a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m +++ /dev/null @@ -1,112 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" - -@interface MGLStyleLayerIntegrationTests : MGLMapViewIntegrationTest -@end - -@implementation MGLStyleLayerIntegrationTests - -- (MGLCircleStyleLayer*)setupCircleStyleLayer { - // Adapted from https://docs.mapbox.com/ios/examples/dds-circle-layer/ - - // "mapbox://examples.2uf7qges" is a tileset ID. For more - // more information, see docs.mapbox.com/help/glossary/tileset-id/ - MGLSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"trees" configurationURL:[NSURL URLWithString:@"mapbox://examples.2uf7qges"]]; - [self.mapView.style addSource:source]; - - MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier: @"tree-style" source:source]; - - // The source name from the source's TileJSON metadata: mapbox.com/api-documentation/maps/#retrieve-tilejson-metadata - layer.sourceLayerIdentifier = @"yoshino-trees-a0puw5"; - - return layer; -} - -- (void)testForInterpolatingExpressionRenderCrashWithEmptyStops { - // Tests: https://github.com/mapbox/mapbox-gl-native/issues/9539 - // Adapted from https://docs.mapbox.com/ios/examples/dds-circle-layer/ - self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039); - self.mapView.zoomLevel = 10.5; - - MGLCircleStyleLayer *layer = [self setupCircleStyleLayer]; - - NSExpression *interpExpression = [NSExpression mgl_expressionForInterpolatingExpression:NSExpression.zoomLevelVariableExpression - withCurveType:MGLExpressionInterpolationModeLinear - parameters:nil - stops:[NSExpression expressionForConstantValue:@{}]]; - - XCTAssertThrowsSpecificNamed((layer.circleColor = interpExpression), NSException, NSInvalidArgumentException); - - [self.mapView.style addLayer:layer]; - [self waitForMapViewToBeRenderedWithTimeout:10]; -} - -- (void)testForSteppingExpressionRenderCrashWithEmptyStops { - // Tests: https://github.com/mapbox/mapbox-gl-native/issues/9539 - // Adapted from https://docs.mapbox.com/ios/examples/dds-circle-layer/ - self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039); - self.mapView.zoomLevel = 10.5; - - MGLCircleStyleLayer *layer = [self setupCircleStyleLayer]; - - NSExpression *steppingExpression = [NSExpression mgl_expressionForSteppingExpression:NSExpression.zoomLevelVariableExpression - fromExpression:[NSExpression expressionForConstantValue:[UIColor greenColor]] - stops:[NSExpression expressionForConstantValue:@{}]]; - - XCTAssertThrowsSpecificNamed((layer.circleColor = steppingExpression), NSException, NSInvalidArgumentException); - - [self.mapView.style addLayer:layer]; - [self waitForMapViewToBeRenderedWithTimeout:10]; -} - -- (void)testForRaisingExceptionsOnStaleStyleObjects { - self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039); - self.mapView.zoomLevel = 10.5; - - MGLVectorTileSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"trees" configurationURL:[NSURL URLWithString:@"mapbox://examples.2uf7qges"]]; - [self.mapView.style addSource:source]; - - self.styleLoadingExpectation = nil; - [self.mapView setStyleURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]]; - [self waitForMapViewToFinishLoadingStyleWithTimeout:10]; - - XCTAssertNotNil(source.description); - XCTAssertThrowsSpecificNamed(source.configurationURL, NSException, MGLInvalidStyleSourceException, @"MGLSource should raise an exception if its core peer got invalidated"); -} - -- (void)testForRaisingExceptionsOnStaleLayerObject { - self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039); - self.mapView.zoomLevel = 10.5; - - MGLPointFeature *feature = [[MGLPointFeature alloc] init]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; - - // Testing generated layers - MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayerID" source:source]; - MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayerID" source:source]; - - [self.mapView.style addSource:source]; - [self.mapView.style addLayer:lineLayer]; - [self.mapView.style addLayer:circleLayer]; - - XCTAssertNoThrow(lineLayer.isVisible); - XCTAssertNoThrow(circleLayer.isVisible); - - XCTAssert(![source.description containsString:@"<unknown>"]); - XCTAssert(![lineLayer.description containsString:@"<unknown>"]); - XCTAssert(![circleLayer.description containsString:@"<unknown>"]); - - self.styleLoadingExpectation = nil; - [self.mapView setStyleURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]]; - [self waitForMapViewToFinishLoadingStyleWithTimeout:10]; - - XCTAssert([source.description containsString:@"<unknown>"]); - XCTAssert([lineLayer.description containsString:@"<unknown>"]); - XCTAssert([circleLayer.description containsString:@"<unknown>"]); - - XCTAssertThrowsSpecificNamed(lineLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated"); - XCTAssertThrowsSpecificNamed(circleLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated"); - - XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:lineLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)"); - XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:circleLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)"); -} -@end diff --git a/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m b/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m deleted file mode 100644 index 22de4c6aa5..0000000000 --- a/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m +++ /dev/null @@ -1,38 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" - -@interface MGLStyleURLIntegrationTest : MGLMapViewIntegrationTest -@end - -@implementation MGLStyleURLIntegrationTest - -- (void)internalTestWithStyleSelector:(SEL)selector { - self.mapView.styleURL = [MGLStyle performSelector:selector]; - [self waitForMapViewToFinishLoadingStyleWithTimeout:5]; -} - - -- (void)testLoadingStreetsStyleURL🔒 { - [self internalTestWithStyleSelector:@selector(streetsStyleURL)]; -} - -- (void)testLoadingOutdoorsStyleURL🔒 { - [self internalTestWithStyleSelector:@selector(outdoorsStyleURL)]; -} - -- (void)testLoadingLightStyleURL🔒 { - [self internalTestWithStyleSelector:@selector(lightStyleURL)]; -} - -- (void)testLoadingDarkStyleURL🔒 { - [self internalTestWithStyleSelector:@selector(darkStyleURL)]; -} - -- (void)testLoadingSatelliteStyleURL🔒 { - [self internalTestWithStyleSelector:@selector(satelliteStyleURL)]; -} - -- (void)testLoadingSatelliteStreetsStyleURL🔒 { - [self internalTestWithStyleSelector:@selector(satelliteStreetsStyleURL)]; -} - -@end diff --git a/platform/ios/Integration Tests/MGLTestLocationManager.h b/platform/ios/Integration Tests/MGLTestLocationManager.h deleted file mode 100644 index e0e6f25bb2..0000000000 --- a/platform/ios/Integration Tests/MGLTestLocationManager.h +++ /dev/null @@ -1,10 +0,0 @@ -#import <XCTest/XCTest.h> -#import <Mapbox/Mapbox.h> -#import "MGLTestUtility.h" - -@interface MGLTestLocationManager : NSObject<MGLLocationManager> -@end - -@interface MGLTestLocationManager() - -@end diff --git a/platform/ios/Integration Tests/MGLTestLocationManager.m b/platform/ios/Integration Tests/MGLTestLocationManager.m deleted file mode 100644 index f9a5a8650f..0000000000 --- a/platform/ios/Integration Tests/MGLTestLocationManager.m +++ /dev/null @@ -1,44 +0,0 @@ -#import "MGLTestLocationManager.h" - -// Used to supply integration tests with a simulated location manager. -// Methods that are empty are not used within integration tests and are -// therefore unimplemented. - -@implementation MGLTestLocationManager - -@synthesize delegate; - -- (CLAuthorizationStatus)authorizationStatus { return kCLAuthorizationStatusAuthorizedAlways; } - -- (void)setHeadingOrientation:(CLDeviceOrientation)headingOrientation { } - -- (CLDeviceOrientation)headingOrientation { return 90; } - -- (void)requestAlwaysAuthorization { } - -- (void)requestWhenInUseAuthorization { } - -- (void)startUpdatingHeading { } - -// Simulate one location update -- (void)startUpdatingLocation -{ - if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) { - CLLocation *location = [[CLLocation alloc] initWithLatitude:37.787357 longitude:-122.39899]; - [self.delegate locationManager:self didUpdateLocations:@[location]]; - } -} - -- (void)stopUpdatingHeading { } - -- (void)stopUpdatingLocation { } - -- (void)dismissHeadingCalibrationDisplay { } - -- (void)dealloc { self.delegate = nil; } - -- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { } - -- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager { return NO; } - -@end diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift deleted file mode 100644 index d33a986beb..0000000000 --- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift +++ /dev/null @@ -1,77 +0,0 @@ -import XCTest - -class MGLMapSnapshotterSwiftTests: MGLMapViewIntegrationTest { - - // Create snapshot options - private class func snapshotterOptions(size: CGSize) -> MGLMapSnapshotOptions { - let camera = MGLMapCamera() - - let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL, camera: camera, size: size) - - let sw = CLLocationCoordinate2D(latitude: 52.3, longitude: 13.0) - let ne = CLLocationCoordinate2D(latitude: 52.5, longitude: 13.2) - options.coordinateBounds = MGLCoordinateBounds(sw:sw, ne:ne) - - return options - } - - func testCapturingSnapshotterInSnapshotCompletion🔒() { - // See the Obj-C testDeallocatingSnapshotterDuringSnapshot - // This Swift test, is essentially the same except for capturing the snapshotter - - let timeout: TimeInterval = 10.0 - let expectation = self.expectation(description: "snapshot") - - let options = MGLMapSnapshotterSwiftTests.snapshotterOptions(size: mapView.bounds.size) - - let backgroundQueue = DispatchQueue.main - - backgroundQueue.async { - let dg = DispatchGroup() - dg.enter() - - DispatchQueue.main.async { - - let snapshotter = MGLMapSnapshotter(options: options) - - snapshotter.start(completionHandler: { (snapshot, error) in - -// // Without capturing snapshotter: -// XCTAssertNil(snapshot) -// XCTAssertNotNil(error) - - // Capture snapshotter - dump(snapshotter) - XCTAssertNotNil(snapshot) - XCTAssertNil(error) - - dg.leave() - }) - } - - dg.notify(queue: .main) { - expectation.fulfill() - } - } - - wait(for: [expectation], timeout: timeout) - } - - func testSnapshotOverlaySwiftErgonomics🔒() { - let options = MGLMapSnapshotterSwiftTests.snapshotterOptions(size: mapView.bounds.size) - let snapshotter = MGLMapSnapshotter(options: options) - let expectation = self.expectation(description: "snapshot") - expectation.expectedFulfillmentCount = 2 - - snapshotter.start(overlayHandler: { (overlay) in - guard let _ = overlay.context.makeImage() else { - XCTFail() - return - } - expectation.fulfill() - }) { (_, _) in - expectation.fulfill() - } - wait(for: [expectation], timeout: 10) - } -} diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m deleted file mode 100644 index 9ef2054dff..0000000000 --- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m +++ /dev/null @@ -1,537 +0,0 @@ -#import "MGLMapViewIntegrationTest.h" -#import "MGLMapSnapshotter_Private.h" - -@interface MGLMapSnapshotter () -@property (nonatomic) BOOL cancelled; -@end - - -@interface MGLMapSnapshotterTest : MGLMapViewIntegrationTest -@end - -// Convenience func to create snapshotter -MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates, CGSize size) { - // Create snapshot options - MGLMapCamera* mapCamera = [[MGLMapCamera alloc] init]; - mapCamera.pitch = 20; - mapCamera.centerCoordinate = coordinates; - MGLMapSnapshotOptions* options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:[MGLStyle satelliteStreetsStyleURL] - camera:mapCamera - size:size]; - options.zoomLevel = 10; - - // Create and start the snapshotter - MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options]; - return snapshotter; -} - -MGLMapSnapshotter* snapshotterWithBounds(MGLCoordinateBounds bounds, CGSize size) { - - MGLMapCamera* mapCamera = [[MGLMapCamera alloc] init]; - MGLMapSnapshotOptions* options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:[MGLStyle satelliteStreetsStyleURL] - camera:mapCamera - size:size]; - options.coordinateBounds = bounds; - - // Create and start the snapshotter - MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options]; - return snapshotter; -} - - - -@implementation MGLMapSnapshotterTest - -- (void)testMultipleSnapshotsWithASingleSnapshotter🔒 { - CGSize size = self.mapView.bounds.size; - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"]; - expectation.expectedFulfillmentCount = 2; - expectation.assertForOverFulfill = YES; - - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - [expectation fulfill]; - }]; - - @try { - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - XCTFail(@"Should not be called - but should it?"); - }]; - XCTFail(@"Should not be called"); - } - @catch (NSException *exception) { - XCTAssert(exception.name == NSInternalInconsistencyException); - [expectation fulfill]; - } - - [self waitForExpectations:@[expectation] timeout:10.0]; -} - -- (void)testDeallocatingSnapshotterDuringSnapshot🔒 { - // See also https://github.com/mapbox/mapbox-gl-native/issues/12336 - - NSTimeInterval timeout = 10.0; - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"]; - CGSize size = self.mapView.bounds.size; - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - // Test triggering to main queue - dispatch_queue_t backgroundQueue = dispatch_get_main_queue(); -// dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - - __weak __typeof__(self) weakself = self; - - dispatch_async(backgroundQueue, ^{ - - dispatch_group_t dg = dispatch_group_create(); - dispatch_group_enter(dg); - - dispatch_async(dispatch_get_main_queue(), ^{ - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - __weak MGLMapSnapshotter *weakSnapshotter = snapshotter; - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - // We expect this completion block to be called with an error - __typeof__(self) strongself = weakself; - - MGLTestAssertNil(strongself, snapshot); - MGLTestAssert(strongself, - ([error.domain isEqualToString:MGLErrorDomain] && error.code == MGLErrorCodeSnapshotFailed), - @"Should have errored"); - MGLTestAssertNil(strongself, weakSnapshotter, @"Snapshotter should have been deallocated"); - - dispatch_group_leave(dg); - }]; - }); - - dispatch_group_notify(dg, dispatch_get_main_queue(), ^{ - [expectation fulfill]; - }); - }); - - [self waitForExpectations:@[expectation] timeout:timeout]; -} - -- (void)testSnapshotterUsingNestedDispatchQueues🔒 { - // This is the opposite pair to the above test `testDeallocatingSnapshotterDuringSnapshot` - // The only significant difference is that the snapshotter is a `__block` variable, so - // its lifetime should continue until it's set to nil in the completion block. - // See also https://github.com/mapbox/mapbox-gl-native/issues/12336 - - NSTimeInterval timeout = 10.0; - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"]; - CGSize size = self.mapView.bounds.size; - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - // Test triggering to main queue - dispatch_queue_t backgroundQueue = dispatch_get_main_queue(); - // dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - - __weak __typeof__(self) weakself = self; - - dispatch_async(backgroundQueue, ^{ - - dispatch_group_t dg = dispatch_group_create(); - dispatch_group_enter(dg); - - dispatch_async(dispatch_get_main_queue(), ^{ - - __block MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - // We expect this completion block to be called with an error - __typeof__(self) strongself = weakself; - MGLTestAssertNotNil(strongself, snapshot); - MGLTestAssertNil(strongself, error, @"Snapshotter should have completed"); - dispatch_group_leave(dg); - snapshotter = nil; - }]; - }); - - dispatch_group_notify(dg, dispatch_get_main_queue(), ^{ - [expectation fulfill]; - }); - }); - - [self waitForExpectations:@[expectation] timeout:timeout]; -} - -- (void)testCancellingSnapshot🔒 { - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"]; - expectation.assertForOverFulfill = YES; - expectation.expectedFulfillmentCount = 1; - - CGSize size = self.mapView.bounds.size; - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - - __weak __typeof__(self) weakself = self; - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - // We expect this completion block to be called with an error - __typeof__(self) strongself = weakself; - - MGLTestAssertNil(strongself, snapshot); - MGLTestAssert(strongself, - ([error.domain isEqualToString:MGLErrorDomain] && error.code == MGLErrorCodeSnapshotFailed), - @"Should have been cancelled"); - MGLTestAssert(strongself, snapshotter.cancelled, @"Should have been cancelled"); - [expectation fulfill]; - }]; - - [snapshotter cancel]; - - [self waitForExpectations:@[expectation] timeout:5.0]; -} - -- (void)testAllocatingSnapshotOnBackgroundQueue🔒 { - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"]; - - CGSize size = self.mapView.bounds.size; - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, QOS_MIN_RELATIVE_PRIORITY); - dispatch_queue_t backgroundQueue = dispatch_queue_create(__PRETTY_FUNCTION__, attr); - - dispatch_async(backgroundQueue, ^{ - - // Create the snapshotter - DO NOT START. - MGLMapSnapshotter* snapshotter = snapshotterWithCoordinates(coord, size); - - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - dispatch_group_leave(group); - }); - - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - - snapshotter = nil; - - dispatch_sync(dispatch_get_main_queue(), ^{ - [expectation fulfill]; - }); - }); - - [self waitForExpectations:@[expectation] timeout:2.0]; -} - -- (void)testSnapshotterFromBackgroundQueueShouldFail🔒 { - CGSize size = self.mapView.bounds.size; - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"]; - expectation.expectedFulfillmentCount = 1; - expectation.assertForOverFulfill = YES; - - __weak __typeof__(self) weakself = self; - - dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, QOS_MIN_RELATIVE_PRIORITY); // also for concurrent - dispatch_queue_t backgroundQueue = dispatch_queue_create(__PRETTY_FUNCTION__, attr); - - // Use dispatch_group to keep the backgroundQueue block around (and - // so also the MGLMapSnapshotter - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); - - dispatch_async(backgroundQueue, ^{ - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - - MGLMapSnapshotCompletionHandler completion = ^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - // The completion block should not be called - MGLTestFail(weakself); - dispatch_group_leave(group); - }; - - @try { - [snapshotter startWithCompletionHandler:completion]; - MGLTestFail(weakself, @"startWithCompletionHandler: should raise an exception"); - } - @catch (NSException *exception) { - MGLTestAssert(weakself, exception.name == NSInvalidArgumentException); - dispatch_group_leave(group); - } - - // Wait for the snapshot to complete - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - - snapshotter = nil; - - dispatch_sync(dispatch_get_main_queue(), ^{ - [expectation fulfill]; - }); - }); - - [self waitForExpectations:@[expectation] timeout:60.0]; -} - -- (void)testMultipleSnapshotters🔒🙁 { - NSUInteger numSnapshots = 8; - CGSize size = self.mapView.bounds.size; - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"]; - expectation.expectedFulfillmentCount = numSnapshots; - expectation.assertForOverFulfill = YES; - - __weak __typeof__(self) weakself = self; - - for (size_t run = 0; run < numSnapshots; run++) { - - float ratio = (float)run/(float)numSnapshots; - float lon = (ratio*120.0) + ((1.0-ratio)*54.0); - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(57.0, lon); - - __block MGLMapSnapshotter *snapshotter; - - // Allocate from an autorelease pool here, to avoid having - // snapshotter retained for longer than we'd like to test. - @autoreleasepool { - snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - } - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - - // This should be the main queue - __typeof__(self) strongself = weakself; - - MGLTestAssertNotNil(strongself, strongself); - - MGLTestAssertNotNil(strongself, snapshot); - MGLTestAssertNotNil(strongself, snapshot.image); - MGLTestAssertNil(strongself, error, @"Snapshot should not error with: %@", error); - - // Change this to XCTAttachmentLifetimeKeepAlways to be able to look at the snapshots after running - XCTAttachment *attachment = [XCTAttachment attachmentWithImage:snapshot.image]; - attachment.lifetime = XCTAttachmentLifetimeDeleteOnSuccess; - [strongself addAttachment:attachment]; - - // Dealloc the snapshotter (by having this line in the block, we - // also retained the snapshotter. Setting to nil should release, as - // this block should be the only thing retaining it (since it was - // allocated from the above autorelease pool) - snapshotter = nil; - - [expectation fulfill]; - }]; - } // end for loop - - [self waitForExpectations:@[expectation] timeout:60.0]; -} - -- (void)testSnapshotPointConversion🔒 { - CGSize size = self.mapView.bounds.size; - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"]; - expectation.expectedFulfillmentCount = 1; - expectation.assertForOverFulfill = YES; - - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - - __weak __typeof__(self) weakself = self; - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - - __typeof__(self) myself = weakself; - - MGLTestAssertNotNil(myself, snapshot); - - CGPoint point = [snapshot pointForCoordinate:coord]; - - CGFloat epsilon = 0.000001; - - MGLTestAssertEqualWithAccuracy(myself, point.x, size.width/2.0, epsilon); - MGLTestAssertEqualWithAccuracy(myself, point.y, size.height/2.0, epsilon); - - CLLocationCoordinate2D coord2 = [snapshot coordinateForPoint:point]; - - MGLTestAssertEqualWithAccuracy(myself, coord.latitude, coord2.latitude, epsilon); - MGLTestAssertEqualWithAccuracy(myself, coord.longitude, coord2.longitude, epsilon); - - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:10.0]; -} - -- (void)testSnapshotPointConversionCoordinateOrdering🔒 { - CGSize size = self.mapView.bounds.size; - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"]; - expectation.expectedFulfillmentCount = 1; - expectation.assertForOverFulfill = YES; - - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - - __weak __typeof__(self) weakself = self; - - [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - - __typeof__(self) myself = weakself; - - CGFloat epsilon = 0.000001; - - MGLTestAssertNotNil(myself, snapshot); - - CLLocationCoordinate2D coordTL = [snapshot coordinateForPoint:CGPointZero]; - - MGLTestAssert(myself, coordTL.longitude < coord.longitude); - MGLTestAssert(myself, coordTL.latitude > coord.latitude); - - // And check point - CGPoint tl = [snapshot pointForCoordinate:coordTL]; - MGLTestAssertEqualWithAccuracy(myself, tl.x, 0.0, epsilon); - MGLTestAssertEqualWithAccuracy(myself, tl.y, 0.0, epsilon); - - CLLocationCoordinate2D coordBR = [snapshot coordinateForPoint:CGPointMake(size.width, size.height)]; - - MGLTestAssert(myself, coordBR.longitude > coord.longitude); - MGLTestAssert(myself, coordBR.latitude < coord.latitude); - - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:10.0]; -} - -- (void)testSnapshotWithOverlayHandlerFailure🔒 { - CGSize size = self.mapView.bounds.size; - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay fails"]; - expectation.expectedFulfillmentCount = 2; - - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - - [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay *snapshotOverlay) { - XCTAssertNotNil(snapshotOverlay); - - UIGraphicsEndImageContext(); - [expectation fulfill]; - } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - XCTAssertNil(snapshot); - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, MGLErrorDomain); - XCTAssertEqual(error.code, MGLErrorCodeSnapshotFailed); - XCTAssertEqualObjects(error.localizedDescription, @"Failed to generate composited snapshot."); - - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:10.0]; -} - -- (void)testSnapshotWithOverlayHandlerSuccess🔒 { - CGSize size = self.mapView.bounds.size; - CGRect snapshotRect = CGRectMake(0, 0, size.width, size.height); - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay succeeds"]; - expectation.expectedFulfillmentCount = 2; - - CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0); - - MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size); - XCTAssertNotNil(snapshotter); - - CGFloat scale = snapshotter.options.scale; - - [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay *snapshotOverlay) { - XCTAssertNotNil(snapshotOverlay); - - CGFloat width = CGBitmapContextGetWidth(snapshotOverlay.context); - CGFloat height = CGBitmapContextGetHeight(snapshotOverlay.context); - - CGRect contextRect = CGContextConvertRectToDeviceSpace(snapshotOverlay.context, CGRectMake(0, 0, 1, 0)); - CGFloat scaleFromContext = contextRect.size.width; - XCTAssertEqual(scale, scaleFromContext); - XCTAssertEqual(width, size.width*scale); - XCTAssertEqual(height, size.height*scale); - - CGContextSetFillColorWithColor(snapshotOverlay.context, [UIColor.greenColor CGColor]); - CGContextSetAlpha(snapshotOverlay.context, 0.2); - CGContextAddRect(snapshotOverlay.context, snapshotRect); - CGContextFillRect(snapshotOverlay.context, snapshotRect); - [expectation fulfill]; - } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - XCTAssertNil(error); - XCTAssertNotNil(snapshot); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:10.0]; -} - -- (void)testSnapshotCoordinatesWithOverlayHandler🔒 { - CGSize size = self.mapView.bounds.size; - - XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay succeeds"]; - expectation.expectedFulfillmentCount = 2; - - CLLocationCoordinate2D london = { .latitude = 51.5074, .longitude = -0.1278 }; - CLLocationCoordinate2D paris = { .latitude = 48.8566, .longitude = 2.3522 }; - - MGLCoordinateBounds bounds = { - .ne = london, - .sw = paris - }; - - MGLMapSnapshotter *snapshotter = snapshotterWithBounds(bounds, size); - XCTAssertNotNil(snapshotter); - - void (^testCoordinates)(id<MGLMapSnapshotProtocol>) = ^(id<MGLMapSnapshotProtocol> snapshot){ - XCTAssertNotNil(snapshot); - - CGPoint londonPoint = [snapshot pointForCoordinate:london]; - CGPoint parisPoint = [snapshot pointForCoordinate:paris]; - - XCTAssertEqualWithAccuracy(londonPoint.x, 0, 0.1); - XCTAssertEqualWithAccuracy(parisPoint.x, size.width, 0.1); - - // Vertically, London and Paris are inset (due to the size vs coordinate bounds) - XCTAssert(parisPoint.y > londonPoint.y); - XCTAssert(londonPoint.y > 0.0); - XCTAssert(parisPoint.y < size.height); - - CLLocationCoordinate2D london2 = [snapshot coordinateForPoint:londonPoint]; - CLLocationCoordinate2D paris2 = [snapshot coordinateForPoint:parisPoint]; - - XCTAssertEqualWithAccuracy(london.latitude, london2.latitude, 0.0000001); - XCTAssertEqualWithAccuracy(london.longitude, london2.longitude, 0.0000001); - XCTAssertEqualWithAccuracy(paris.latitude, paris2.latitude, 0.0000001); - XCTAssertEqualWithAccuracy(paris.longitude, paris2.longitude, 0.0000001); - }; - - [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay *snapshotOverlay) { - XCTAssert([snapshotOverlay conformsToProtocol:@protocol(MGLMapSnapshotProtocol)]); - testCoordinates((id<MGLMapSnapshotProtocol>)snapshotOverlay); - - [expectation fulfill]; - } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { - XCTAssert([snapshot conformsToProtocol:@protocol(MGLMapSnapshotProtocol)]); - testCoordinates((id<MGLMapSnapshotProtocol>)snapshot); - - [expectation fulfill]; - }]; - - [self waitForExpectations:@[expectation] timeout:10.0]; -} - - -@end diff --git a/platform/ios/Integration Tests/integration-Bridging-Header.h b/platform/ios/Integration Tests/integration-Bridging-Header.h deleted file mode 100644 index 55b44ea57b..0000000000 --- a/platform/ios/Integration Tests/integration-Bridging-Header.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// -#import "MGLMapViewIntegrationTest.h" - |