diff options
author | Asheem Mamoowala <asheem.mamoowala@mapbox.com> | 2018-04-02 16:15:25 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-02 16:15:25 -0700 |
commit | 099fcc3b3c72b117e93d4da39ee6f70c6c5a2bc8 (patch) | |
tree | 523c8c884404f82075702b6ea707e2b2b8015089 /platform/ios | |
parent | c3079c6155d7ba2a0c8dd36571f17d7652a2092e (diff) | |
download | qtlocation-mapboxgl-099fcc3b3c72b117e93d4da39ee6f70c6c5a2bc8.tar.gz |
Use a host interface for CustomLayer instead of function pointers (#11553)
Use a host interface for CustomLayer instead of function pointers
Co-authored-by: Julian Rex <julian.rex@mapbox.com>
Diffstat (limited to 'platform/ios')
-rw-r--r-- | platform/ios/Integration Tests/MBGLIntegrationTests.m | 217 |
1 files changed, 201 insertions, 16 deletions
diff --git a/platform/ios/Integration Tests/MBGLIntegrationTests.m b/platform/ios/Integration Tests/MBGLIntegrationTests.m index db6cc13930..7b82f41b57 100644 --- a/platform/ios/Integration Tests/MBGLIntegrationTests.m +++ b/platform/ios/Integration Tests/MBGLIntegrationTests.m @@ -1,6 +1,6 @@ #import <XCTest/XCTest.h> - -@import Mapbox; +#import <objc/message.h> +#import <Mapbox/Mapbox.h> @interface MBGLIntegrationTests : XCTestCase <MGLMapViewDelegate> @@ -11,8 +11,11 @@ @implementation MBGLIntegrationTests { XCTestExpectation *_styleLoadingExpectation; + XCTestExpectation *_renderFinishedExpectation; } +#pragma mark - Setup/Teardown + - (void)setUp { [super setUp]; @@ -32,6 +35,16 @@ [window makeKeyAndVisible]; } +- (void)tearDown { + _styleLoadingExpectation = nil; + self.mapView = nil; + self.style = nil; + + [super tearDown]; +} + +#pragma mark - MGLMapViewDelegate + - (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { XCTAssertNotNil(mapView.style); XCTAssertEqual(mapView.style, style); @@ -39,30 +52,112 @@ [_styleLoadingExpectation fulfill]; } -- (void)tearDown { - _styleLoadingExpectation = nil; - self.mapView = nil; +- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(__unused BOOL)fullyRendered { + [_renderFinishedExpectation fulfill]; + _renderFinishedExpectation = nil; +} - [super tearDown]; +#pragma mark - Utilities + +- (void)waitForMapViewToBeRendered { + [self.mapView setNeedsDisplay]; + _renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"]; + [self waitForExpectations:@[_renderFinishedExpectation] timeout:1]; } - (MGLStyle *)style { return self.mapView.style; } +#pragma mark - Tests + +// 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) = ^{ - 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]; - id retrievedLayer = [self.style layerWithIdentifier:@"gl-layer"]; - XCTAssertNotNil(retrievedLayer); - [self.style removeLayer:retrievedLayer]; + retrievedLayer = [self.style layerWithIdentifier:@"gl-layer"]; + XCTAssertNotNil(retrievedLayer); + + [self.style removeLayer:retrievedLayer]; + [self waitForMapViewToBeRendered]; + } + + XCTAssertNil(retrievedLayer); }; addRemoveGLLayer(); @@ -70,8 +165,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"]; + _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; + [self.mapView setStyleURL:styleURL]; + [self waitForExpectations:@[_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); + + _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 + |