diff options
Diffstat (limited to 'platform/ios/Integration Tests/MBGLIntegrationTests.m')
-rw-r--r-- | platform/ios/Integration Tests/MBGLIntegrationTests.m | 215 |
1 files changed, 170 insertions, 45 deletions
diff --git a/platform/ios/Integration Tests/MBGLIntegrationTests.m b/platform/ios/Integration Tests/MBGLIntegrationTests.m index db6cc13930..4f42c5a13f 100644 --- a/platform/ios/Integration Tests/MBGLIntegrationTests.m +++ b/platform/ios/Integration Tests/MBGLIntegrationTests.m @@ -1,68 +1,103 @@ -#import <XCTest/XCTest.h> +#import "MGLMapViewIntegrationTest.h" -@import Mapbox; +@interface MBGLIntegrationTests : MGLMapViewIntegrationTest +@end -@interface MBGLIntegrationTests : XCTestCase <MGLMapViewDelegate> +@implementation MBGLIntegrationTests -@property (nonatomic) MGLMapView *mapView; -@property (nonatomic) MGLStyle *style; +#pragma mark - Tests -@end +- (void)waitForMapViewToBeRendered { + [self waitForMapViewToBeRenderedWithTimeout:1]; +} + +// 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; -@implementation MBGLIntegrationTests { - XCTestExpectation *_styleLoadingExpectation; + XCTAssertNil(weakLayer); } -- (void)setUp { - [super setUp]; +- (void)testAddingRemovingOpenGLLayerWithoutRendering { + XCTAssertNotNil(self.style); - [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; - NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; - self.mapView = [[MGLMapView alloc] initWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL]; - self.mapView.delegate = self; - if (!self.mapView.style) { - _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; - [self waitForExpectationsWithTimeout:1 handler:nil]; - } + void(^addRemoveGLLayer)(void) = ^{ + __weak id weakLayer = nil; - UIView *superView = [[UIView alloc] initWithFrame:UIScreen.mainScreen.bounds]; - [superView addSubview:self.mapView]; - UIWindow *window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; - [window addSubview:superView]; - [window makeKeyAndVisible]; -} + @autoreleasepool { + MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; + [self.style insertLayer:layer atIndex:0]; + weakLayer = layer; -- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { - XCTAssertNotNil(mapView.style); - XCTAssertEqual(mapView.style, style); + // Nil the layer prior to remove to ensure it's being retained + layer = nil; + [self.style removeLayer:weakLayer]; + } + + XCTAssertNil(weakLayer); + }; - [_styleLoadingExpectation fulfill]; + addRemoveGLLayer(); + addRemoveGLLayer(); + addRemoveGLLayer(); } -- (void)tearDown { - _styleLoadingExpectation = nil; - self.mapView = nil; +- (void)testReusingOpenGLLayerIdentifier { + __weak MGLOpenGLStyleLayer *weakLayer2; - [super tearDown]; -} + @autoreleasepool { + MGLOpenGLStyleLayer *layer1 = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; + [self.style insertLayer:layer1 atIndex:0]; + [self waitForMapViewToBeRendered]; + [self.style removeLayer:layer1]; -- (MGLStyle *)style { - return self.mapView.style; + 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) = ^{ - MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; - [self.style insertLayer:layer atIndex:0]; - layer = nil; - [[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]]; + __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); - id retrievedLayer = [self.style layerWithIdentifier:@"gl-layer"]; - XCTAssertNotNil(retrievedLayer); - [self.style removeLayer:retrievedLayer]; + [self.style removeLayer:retrievedLayer]; + [self waitForMapViewToBeRendered]; + } + + XCTAssertNil(retrievedLayer); }; addRemoveGLLayer(); @@ -70,8 +105,98 @@ addRemoveGLLayer(); } -//- (void)testOpenGLLayerDoesNotLeakWhenCreatedAndDestroyedWithoutAddingToStyle { -// XCTFail(@"Not yet implemented"); -//} +- (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:1 handler:nil]; + + MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; + weakLayer = layer; + [mapView2.style insertLayer:layer atIndex:0]; + layer = nil; + + [self waitForMapViewToBeRendered]; + } + XCTAssertNil(weakLayer); +} @end + |