summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Rex <julian.rex@mapbox.com>2019-09-18 18:13:07 -0400
committerGitHub <noreply@github.com>2019-09-18 18:13:07 -0400
commit2b08c1d7bf9e867d6450feb6a246ce36dcdf2cd3 (patch)
tree8041d2169d2c26041c004c3336de08d031a3f9e8
parent7bca176beaf4dcae2263eeabee82fd7b6412654b (diff)
downloadqtlocation-mapboxgl-2b08c1d7bf9e867d6450feb6a246ce36dcdf2cd3.tar.gz
[ios, macos] Fix MGLOfflinePack invalidate crash (#15582)
-rw-r--r--platform/darwin/src/MGLOfflinePack.mm11
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm4
-rw-r--r--platform/darwin/test/MGLOfflinePackTests.mm (renamed from platform/darwin/test/MGLOfflinePackTests.m)18
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm198
-rw-r--r--platform/darwin/test/MGLTestAssertionHandler.h18
-rw-r--r--platform/darwin/test/MGLTestAssertionHandler.m77
-rw-r--r--platform/default/include/mbgl/storage/offline_database.hpp1
-rw-r--r--platform/default/src/mbgl/storage/offline_database.cpp9
-rw-r--r--platform/ios/CHANGELOG.md1
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj16
-rw-r--r--platform/macos/CHANGELOG.md1
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj14
12 files changed, 354 insertions, 14 deletions
diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm
index 0f2e8180fa..5f4ae9c838 100644
--- a/platform/darwin/src/MGLOfflinePack.mm
+++ b/platform/darwin/src/MGLOfflinePack.mm
@@ -135,10 +135,15 @@ private:
- (void)invalidate {
MGLLogInfo(@"Invalidating pack.");
MGLAssert(_state != MGLOfflinePackStateInvalid, @"Cannot invalidate an already invalid offline pack.");
+ MGLAssert(self.mbglOfflineRegion, @"Should have a valid region");
- self.state = MGLOfflinePackStateInvalid;
- _mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr);
- self.mbglOfflineRegion = nil;
+ @synchronized (self) {
+ self.state = MGLOfflinePackStateInvalid;
+ if (self.mbglOfflineRegion) {
+ _mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr);
+ }
+ self.mbglOfflineRegion = nil;
+ }
}
- (void)setState:(MGLOfflinePackState)state {
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 93f986a518..32d1735bc0 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -426,11 +426,15 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
- (void)_removePack:(MGLOfflinePack *)pack withCompletionHandler:(MGLOfflinePackRemovalCompletionHandler)completion {
mbgl::OfflineRegion *mbglOfflineRegion = pack.mbglOfflineRegion;
+
[pack invalidate];
+
if (!mbglOfflineRegion) {
+ MGLAssert(pack.state == MGLOfflinePackStateInvalid, @"State should be invalid");
completion(nil);
return;
}
+
_mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) {
NSError *error;
if (exception) {
diff --git a/platform/darwin/test/MGLOfflinePackTests.m b/platform/darwin/test/MGLOfflinePackTests.mm
index a33665ff0a..6b454ee8ca 100644
--- a/platform/darwin/test/MGLOfflinePackTests.m
+++ b/platform/darwin/test/MGLOfflinePackTests.mm
@@ -1,5 +1,7 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import "MGLOfflinePack_Private.h"
+#import "MGLTestAssertionHandler.h"
@interface MGLOfflinePackTests : XCTestCase
@@ -18,6 +20,22 @@
XCTAssertThrowsSpecificNamed([invalidPack suspend], NSException, MGLInvalidOfflinePackException, @"Invalid offline pack should raise an exception when being suspended.");
}
+- (void)testInvalidatingAnInvalidPack {
+ MGLOfflinePack *invalidPack = [[MGLOfflinePack alloc] init];
+
+ XCTAssertThrowsSpecificNamed([invalidPack invalidate], NSException, NSInternalInconsistencyException, @"Invalid offline pack should raise an exception when being invalidated.");
+
+ // Now try again, without asserts
+ NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler];
+ MGLTestAssertionHandler *newHandler = [[MGLTestAssertionHandler alloc] initWithTestCase:self];
+ [[[NSThread currentThread] threadDictionary] setValue:newHandler forKey:NSAssertionHandlerKey];
+
+ // Make sure this doesn't crash without asserts
+ [invalidPack invalidate];
+
+ [[[NSThread currentThread] threadDictionary] setValue:oldHandler forKey:NSAssertionHandlerKey];
+}
+
- (void)testProgressBoxing {
MGLOfflinePackProgress progress = {
.countOfResourcesCompleted = 3,
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm
index ee4bcc2c65..b44d4c51cd 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.mm
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -1,15 +1,16 @@
#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
#import "MGLOfflineStorage_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
-
-#import <XCTest/XCTest.h>
+#import "MGLTestAssertionHandler.h"
#include <mbgl/util/run_loop.hpp>
#pragma clang diagnostic ignored "-Wshadow"
+
@interface MGLOfflineStorageTests : XCTestCase <MGLOfflineStorageDelegate>
@end
@@ -34,7 +35,7 @@
- (void)setUp {
[super setUp];
-
+
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
XCTestExpectation *expectation = [self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
@@ -310,6 +311,197 @@
XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks - 1, @"Removed pack should have been removed from the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks or -testAddPack.");
}
+- (void)addPacks:(NSInteger)count {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"];
+
+ NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8];
+
+ MGLCoordinateBounds bounds[] = {
+ {{51.5, -0.2}, {51.6, -0.1}}, // London
+ {{60.1, 24.8}, {60.3, 25.1}}, // Helsinki
+ {{38.9, -77.1}, {38.9, -77.0}}, // DC
+ {{37.7, -122.5}, {37.9, -122.4}} // SF
+ };
+
+ int arraySize = sizeof(bounds)/sizeof(bounds[0]);
+
+ count = MIN(count, arraySize);
+
+ dispatch_group_t group = dispatch_group_create();
+
+ for (int i = 0; i < count; i++) {
+
+ dispatch_group_enter(group);
+ MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:styleURL bounds:bounds[i] fromZoomLevel:20 toZoomLevel:20];
+ NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{
+ @"index": @(i)
+ }];
+
+ [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region
+ withContext:context
+ completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) {
+ XCTAssertNotNil(pack);
+ XCTAssertNil(error);
+
+ dispatch_group_leave(group);
+ }];
+ }
+
+ dispatch_group_notify(group, dispatch_get_main_queue(), ^{
+ [expectation fulfill];
+ });
+
+ [self waitForExpectations:@[expectation] timeout:1.0];
+}
+
+- (void)testRemovePackTwiceInSuccession {
+
+ [self addPacks:1];
+
+ NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
+
+ MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs.lastObject;
+ XCTAssertNotNil(pack, @"Added pack should still exist.");
+
+ [self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
+ NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
+ return changeKind == NSKeyValueChangeRemoval && indices.count == 1;
+ }];
+
+ XCTestExpectation *completionHandlerExpectation = [self expectationWithDescription:@"remove pack completion handler"];
+
+ [[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:nil];
+
+ NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler];
+ MGLTestAssertionHandler *newHandler = [[MGLTestAssertionHandler alloc] initWithTestCase:self];
+
+ [[[NSThread currentThread] threadDictionary] setValue:newHandler forKey:NSAssertionHandlerKey];
+
+ [[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
+ XCTAssertEqual(pack.state, MGLOfflinePackStateInvalid, @"Removed pack should be invalid in the completion handler.");
+ [completionHandlerExpectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:5 handler:nil];
+
+ [[[NSThread currentThread] threadDictionary] setValue:oldHandler forKey:NSAssertionHandlerKey];
+
+ XCTAssertEqual(pack.state, MGLOfflinePackStateInvalid, @"Removed pack should have been invalidated synchronously.");
+
+ XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks - 1, @"Removed pack should have been removed from the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks or -testAddPack.");
+
+ NSLog(@"Test `%@` complete", NSStringFromSelector(_cmd));
+}
+
+- (void)test15536RemovePacksWhileReloading {
+
+ // This test triggers
+ //
+ // throw std::runtime_error("Malformed offline region definition");
+ //
+ // in offline.cpp
+ //
+ // Reloading packs, while trying to remove them is currently problematic.
+
+ [self addPacks:4];
+
+ NSInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
+ XCTAssert(countOfPacks > 0);
+
+ // Now delete packs one by one
+ XCTestExpectation *expectation = [self expectationWithDescription:@"All packs removed"];
+ expectation.expectedFulfillmentCount = countOfPacks;
+
+ MGLOfflineStorage *storage = [MGLOfflineStorage sharedOfflineStorage];
+ NSArray *packs = [storage.packs copy];
+
+ // Simulate what happens the first time sharedOfflineStorage is accessed
+ [storage reloadPacks];
+
+ NSArray *validPacks = [packs filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
+ MGLOfflinePack *pack = (MGLOfflinePack*)evaluatedObject;
+ return pack.state != MGLOfflinePackStateInvalid;
+ }]];
+
+ NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler];
+ MGLTestAssertionHandler *newHandler = [[MGLTestAssertionHandler alloc] initWithTestCase:self];
+
+ [[[NSThread currentThread] threadDictionary] setValue:newHandler forKey:NSAssertionHandlerKey];
+
+ for (MGLOfflinePack *pack in validPacks) {
+ [storage removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
+ [expectation fulfill];
+ }];
+ }
+
+ [[[NSThread currentThread] threadDictionary] setValue:oldHandler forKey:NSAssertionHandlerKey];
+
+ [self waitForExpectations:@[expectation] timeout:10.0];
+
+ // TODO: What should we expect here? All packs removed?
+
+ NSLog(@"Test `%@` complete", NSStringFromSelector(_cmd));
+}
+
+// Test to explore https://github.com/mapbox/mapbox-gl-native/issues/15536
+- (void)test15536RemovePacksOnBackgroundQueueWhileReloading {
+
+ [self addPacks:4];
+
+ NSInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
+ XCTAssert(countOfPacks > 0);
+
+ // Now delete packs one by one
+ dispatch_queue_t queue = dispatch_queue_create("com.mapbox.testRemovePacks", DISPATCH_QUEUE_SERIAL);
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"all packs removed"];
+ expectation.expectedFulfillmentCount = countOfPacks;
+
+ MGLOfflineStorage *storage = [MGLOfflineStorage sharedOfflineStorage];
+
+ // Simulate what happens the first time sharedOfflineStorage is accessed
+ [storage reloadPacks];
+
+// NSArray *packs = [storage.packs copy];
+
+ dispatch_async(queue, ^{
+ NSArray *packs = storage.packs;
+ NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler];
+ MGLTestAssertionHandler *newHandler = [[MGLTestAssertionHandler alloc] initWithTestCase:self];
+
+ [[[NSThread currentThread] threadDictionary] setValue:newHandler forKey:NSAssertionHandlerKey];
+
+ NSArray *validPacks = [packs filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
+ MGLOfflinePack *pack = (MGLOfflinePack*)evaluatedObject;
+ return pack.state != MGLOfflinePackStateInvalid;
+ }]];
+
+ for (MGLOfflinePack *pack in validPacks) {
+ // NOTE: pack can be invalid, as we have two threads potentially
+ // modifying the same MGLOfflinePack.
+
+ dispatch_group_t group = dispatch_group_create();
+ dispatch_group_enter(group);
+ [storage removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
+ dispatch_group_leave(group);
+ }];
+ dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+
+ [expectation fulfill];
+ }
+
+ [[[NSThread currentThread] threadDictionary] setValue:oldHandler forKey:NSAssertionHandlerKey];
+ });
+
+ [self waitForExpectations:@[expectation] timeout:60.0];
+
+ // TODO: What should we expect here? All packs removed?
+
+ NSLog(@"Test `%@` complete", NSStringFromSelector(_cmd));
+}
+
- (void)testCountOfBytesCompleted {
XCTAssertGreaterThan([MGLOfflineStorage sharedOfflineStorage].countOfBytesCompleted, 0UL);
}
diff --git a/platform/darwin/test/MGLTestAssertionHandler.h b/platform/darwin/test/MGLTestAssertionHandler.h
new file mode 100644
index 0000000000..f1aa39921e
--- /dev/null
+++ b/platform/darwin/test/MGLTestAssertionHandler.h
@@ -0,0 +1,18 @@
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Use to catch or log assertions that occur in dispatch blocks, timers or
+// other asynchronous operations.
+@interface MGLTestAssertionHandler : NSAssertionHandler
+
+- (instancetype)initWithTestCase:(XCTestCase *)testCase;
+@property (nonatomic, weak) XCTestCase *testCase;
+
+// If YES, use `_XCTPreformattedFailureHandler` to "fail" the test,
+// otherwise log the assert.
+@property (nonatomic) BOOL shouldFail;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/test/MGLTestAssertionHandler.m b/platform/darwin/test/MGLTestAssertionHandler.m
new file mode 100644
index 0000000000..4b504427b5
--- /dev/null
+++ b/platform/darwin/test/MGLTestAssertionHandler.m
@@ -0,0 +1,77 @@
+#import "MGLTestAssertionHandler.h"
+
+@implementation MGLTestAssertionHandler
+
+- (instancetype)initWithTestCase:(XCTestCase *)testCase {
+ if ((self = [super init])) {
+ _testCase = testCase;
+ }
+ return self;
+}
+
+- (void)handleFailureInMethod:(SEL)selector
+ object:(id)object
+ file:(NSString *)fileName
+ lineNumber:(NSInteger)line
+ description:(NSString *)format, ...
+{
+ va_list args;
+ va_start(args, format);
+ NSString *description = [[NSString alloc] initWithFormat:format arguments:args];
+ va_end(args);
+
+ NSString *condition = [NSString stringWithFormat:
+ @"`[%@ %@]`",
+ object, NSStringFromSelector(selector)
+ ];
+
+ if (self.testCase && self.shouldFail) {
+ _XCTPreformattedFailureHandler(self.testCase,
+ YES,
+ fileName,
+ line,
+ condition,
+ description
+ );
+ }
+ else {
+ NSLog(@"Assertion Failure: %@:%lu: %@ - %@",
+ fileName,
+ line,
+ condition,
+ description);
+ }
+}
+
+- (void)handleFailureInFunction:(NSString *)functionName
+ file:(NSString *)fileName
+ lineNumber:(NSInteger)line
+ description:(NSString *)format, ...
+{
+ va_list args;
+ va_start(args, format);
+ NSString *description = [[NSString alloc] initWithFormat:format arguments:args];
+ va_end(args);
+
+ NSString *condition = [NSString stringWithFormat:
+ @"`%@`",
+ functionName];
+
+ if (self.testCase && self.shouldFail) {
+ _XCTPreformattedFailureHandler(self.testCase,
+ YES,
+ fileName,
+ line,
+ condition,
+ description);
+ }
+ else {
+ NSLog(@"Assertion Failure: %@:%lu: %@ - %@",
+ fileName,
+ line,
+ condition,
+ description);
+ }
+}
+@end
+
diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp
index e19dcfade9..96b867eaa6 100644
--- a/platform/default/include/mbgl/storage/offline_database.hpp
+++ b/platform/default/include/mbgl/storage/offline_database.hpp
@@ -98,6 +98,7 @@ private:
void initialize();
void handleError(const mapbox::sqlite::Exception&, const char* action);
void handleError(const util::IOException&, const char* action);
+ void handleError(const std::runtime_error& ex, const char* action);
void removeExisting();
void removeOldCacheTable();
diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp
index 83eea7bcc4..133e1f7992 100644
--- a/platform/default/src/mbgl/storage/offline_database.cpp
+++ b/platform/default/src/mbgl/storage/offline_database.cpp
@@ -124,6 +124,10 @@ void OfflineDatabase::handleError(const util::IOException& ex, const char* actio
Log::Error(Event::Database, ex.code, "Can't %s: %s", action, ex.what());
}
+void OfflineDatabase::handleError(const std::runtime_error& ex, const char* action) {
+ Log::Error(Event::Database, -1, "Can't %s: %s", action, ex.what());
+}
+
void OfflineDatabase::removeExisting() {
Log::Warning(Event::Database, "Removing existing incompatible offline database");
@@ -1059,6 +1063,11 @@ expected<OfflineRegionDefinition, std::exception_ptr> OfflineDatabase::getRegion
} catch (const mapbox::sqlite::Exception& ex) {
handleError(ex, "load region");
return unexpected<std::exception_ptr>(std::current_exception());
+} catch (const std::runtime_error& ex) {
+ // Catch errors from malformed offline region definitions
+ // and skip them (as above).
+ handleError(ex, "load region");
+ return unexpected<std::exception_ptr>(std::current_exception());
}
expected<OfflineRegionStatus, std::exception_ptr> OfflineDatabase::getRegionCompletedStatus(int64_t regionID) try {
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 089cc18606..6329771518 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -23,6 +23,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Enabled use of `MGLSymbolStyleLayer.textOffset` option together with `MGLSymbolStyleLayer.textVariableAnchor` (if `MGLSymbolStyleLayer.textRadialOffset` option is not provided). ([#15542](https://github.com/mapbox/mapbox-gl-native/pull/15542))
* Fixed an issue with the appearance of the compass text in iOS 13. ([#15547](https://github.com/mapbox/mapbox-gl-native/pull/15547))
* Fixed a bug where the completion block passed to `-[MGLMapView flyToCamera:completionHandler:` (and related methods) wouldn't be called. ([#15473](https://github.com/mapbox/mapbox-gl-native/pull/15473))
+* Fixed a crash when `-[MGLOfflinePack invalidate]` is called on different threads. ([#15582](https://github.com/mapbox/mapbox-gl-native/pull/15582))
### User interaction
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 9ac5d564fe..20001c26a8 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -503,6 +503,7 @@
ACD0245B2187EABA00D8C8A7 /* MMEMetricsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = ACD024542187EAAF00D8C8A7 /* MMEMetricsManager.m */; };
ACD0245E2187EACB00D8C8A7 /* MMEMetrics.m in Sources */ = {isa = PBXBuildFile; fileRef = ACD024572187EAAF00D8C8A7 /* MMEMetrics.m */; };
ACD0245F2187EACB00D8C8A7 /* MMEMetrics.m in Sources */ = {isa = PBXBuildFile; fileRef = ACD024572187EAAF00D8C8A7 /* MMEMetrics.m */; };
+ CA0B3C022329DE9A00E4B493 /* MGLTestAssertionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */; };
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27912076C804001CE5B7 /* MGLShapeSourceTests.m */; };
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */; };
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA1B4A502099FB2200EDD491 /* MGLMapSnapshotterTest.m */; };
@@ -523,6 +524,7 @@
CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */; };
CAA69DA4206DCD0E007279CD /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; };
CAA69DA5206DCD0E007279CD /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ CAAA65D92321BBA900F08A39 /* MGLTestAssertionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */; };
CABE5DAD2072FAB40003AF3C /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
CAD9D0AA22A86D6F001B25EE /* MGLResourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */; };
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */; };
@@ -551,7 +553,7 @@
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2DBBCD1D51E80400D38FF9 /* MGLStyleLayerTests.m */; };
DA2E88561CC036F400F24E7B /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
DA2E88611CC0382C00F24E7B /* MGLGeometryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */; };
- DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */; };
+ DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.mm */; };
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */; };
DA2E88651CC0382C00F24E7B /* MGLStyleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */; };
DA35A29E1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1211,6 +1213,8 @@
CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfigurationTests.m; sourceTree = "<group>"; };
CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleURLIntegrationTest.m; sourceTree = "<group>"; };
CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = "<group>"; };
+ CAAA65D72321BBA900F08A39 /* MGLTestAssertionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestAssertionHandler.h; path = ../../darwin/test/MGLTestAssertionHandler.h; sourceTree = "<group>"; };
+ CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLTestAssertionHandler.m; path = ../../darwin/test/MGLTestAssertionHandler.m; sourceTree = "<group>"; };
CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLResourceTests.mm; path = ../../darwin/test/MGLResourceTests.mm; sourceTree = "<group>"; };
CAE7AD5320F46EF5003B6782 /* integration-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "integration-Bridging-Header.h"; sourceTree = "<group>"; };
CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MGLMapSnapshotterSwiftTests.swift; sourceTree = "<group>"; };
@@ -1244,7 +1248,7 @@
DA2E88511CC036F400F24E7B /* test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = test.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DA2E88551CC036F400F24E7B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLGeometryTests.mm; path = ../../darwin/test/MGLGeometryTests.mm; sourceTree = "<group>"; };
- DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = "<group>"; };
+ DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflinePackTests.mm; path = ../../darwin/test/MGLOfflinePackTests.mm; sourceTree = "<group>"; };
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = "<group>"; };
DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; };
DA33895F1FA3EAB7001EA329 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Foundation.strings"; sourceTree = "<group>"; };
@@ -1758,6 +1762,8 @@
4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */,
A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */,
A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */,
+ CAAA65D72321BBA900F08A39 /* MGLTestAssertionHandler.h */,
+ CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */,
);
name = "Test Helpers";
sourceTree = "<group>";
@@ -2084,7 +2090,7 @@
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */,
96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */,
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
- DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */,
+ DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.mm */,
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */,
55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */,
35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */,
@@ -3219,6 +3225,7 @@
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */,
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */,
077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */,
+ CA0B3C022329DE9A00E4B493 /* MGLTestAssertionHandler.m in Sources */,
CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm in Sources */,
CA4F3BE223107793008BAFEA /* MGLCameraTransitionTests.mm in Sources */,
CA4C54FE2324948100A81659 /* MGLSourceTests.swift in Sources */,
@@ -3264,6 +3271,7 @@
files = (
A4DE3DCC23038CCA005B3473 /* MGLMockGestureRecognizers.m in Sources */,
A4DE3DCB23038C98005B3473 /* MGLMockGestureRecognizers.h in Sources */,
+ CAAA65D92321BBA900F08A39 /* MGLTestAssertionHandler.m in Sources */,
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */,
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */,
409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
@@ -3302,7 +3310,7 @@
9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */,
409D0A0D1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift in Sources */,
9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.mm in Sources */,
- DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
+ DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.mm in Sources */,
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
07D8C6FF1F67562C00381808 /* MGLComputedShapeSourceTests.m in Sources */,
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */,
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 888d4c5267..fc59457a26 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -19,6 +19,7 @@
* Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. ([#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560))
* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapShot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
* Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. ([#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581))
+* Fixed a crash when `-[MGLOfflinePack invalidate]` is called on different threads. ([#15582](https://github.com/mapbox/mapbox-gl-native/pull/15582))
### Styles and rendering
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 50f592a4bc..226bc62312 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -128,6 +128,8 @@
9654C12B1FFC38E000DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12A1FFC38E000DB6A19 /* MGLPolyline_Private.h */; };
9654C12D1FFC394700DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12C1FFC394700DB6A19 /* MGLPolygon_Private.h */; };
96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027331E57C9A7004B8E66 /* Localizable.strings */; };
+ CA0B3C072329F7E700E4B493 /* MGLTestAssertionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0B3C052329F7E600E4B493 /* MGLTestAssertionHandler.m */; };
+ CA0B3C092329FB4800E4B493 /* MGLOfflinePackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA0B3C082329FB4800E4B493 /* MGLOfflinePackTests.mm */; };
CA4045C7216720D700B356E1 /* MGLCluster.h in Headers */ = {isa = PBXBuildFile; fileRef = CA4045C4216720D700B356E1 /* MGLCluster.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */; };
CA9461A620884CCB0015EB12 /* MGLAnnotationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA9461A520884CCB0015EB12 /* MGLAnnotationTests.m */; };
@@ -280,7 +282,6 @@
DAE6C3BF1CC31F2E00DB3429 /* mapbox.pdf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C3BC1CC31F2E00DB3429 /* mapbox.pdf */; };
DAE6C3C21CC31F4500DB3429 /* Mapbox.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3C11CC31F4500DB3429 /* Mapbox.h */; settings = {ATTRIBUTES = (Public, ); }; };
DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */; };
- DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */; };
DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */; };
DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */; };
DAE7DEC41E24549F007505A6 /* MGLNSStringAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */; };
@@ -467,6 +468,9 @@
96E027391E57C9B9004B8E66 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
96E0273A1E57C9BB004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
96E0273B1E57C9BC004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ CA0B3C042329F7E600E4B493 /* MGLTestAssertionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLTestAssertionHandler.h; path = ../../darwin/test/MGLTestAssertionHandler.h; sourceTree = "<group>"; };
+ CA0B3C052329F7E600E4B493 /* MGLTestAssertionHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLTestAssertionHandler.m; path = ../../darwin/test/MGLTestAssertionHandler.m; sourceTree = "<group>"; };
+ CA0B3C082329FB4800E4B493 /* MGLOfflinePackTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflinePackTests.mm; path = ../../darwin/test/MGLOfflinePackTests.mm; sourceTree = "<group>"; };
CA4045C4216720D700B356E1 /* MGLCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCluster.h; sourceTree = "<group>"; };
CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = "<group>"; };
CA9461A520884CCB0015EB12 /* MGLAnnotationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationTests.m; path = test/MGLAnnotationTests.m; sourceTree = SOURCE_ROOT; };
@@ -693,7 +697,6 @@
DAE6C3C11CC31F4500DB3429 /* Mapbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mapbox.h; path = src/Mapbox.h; sourceTree = SOURCE_ROOT; };
DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLGeometryTests.mm; path = ../../darwin/test/MGLGeometryTests.mm; sourceTree = "<group>"; };
- DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = "<group>"; };
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = "<group>"; };
DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; };
DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLNSStringAdditionsTests.m; path = ../../darwin/test/MGLNSStringAdditionsTests.m; sourceTree = "<group>"; };
@@ -870,6 +873,8 @@
4031AD001E9FD61000A3EA26 /* Test Helpers */ = {
isa = PBXGroup;
children = (
+ CA0B3C042329F7E600E4B493 /* MGLTestAssertionHandler.h */,
+ CA0B3C052329F7E600E4B493 /* MGLTestAssertionHandler.m */,
4031AD011E9FD6A300A3EA26 /* MGLSDKTestHelpers.swift */,
);
name = "Test Helpers";
@@ -1195,7 +1200,7 @@
076171C4213A0DC200668A35 /* MGLMapViewTests.m */,
1F95931A1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm */,
DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */,
- DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */,
+ CA0B3C082329FB4800E4B493 /* MGLOfflinePackTests.mm */,
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */,
55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */,
35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */,
@@ -1737,6 +1742,7 @@
1F7454AB1ED1DDBD00021D39 /* MGLLightTest.mm in Sources */,
07A240941F675674002C8210 /* MGLComputedShapeSourceTests.m in Sources */,
DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */,
+ CA0B3C072329F7E700E4B493 /* MGLTestAssertionHandler.m in Sources */,
DA695424215B1E6C002041A4 /* MGLMapCameraTests.m in Sources */,
920A3E591E6F859D00C16EFC /* MGLSourceQueryTests.m in Sources */,
DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
@@ -1752,6 +1758,7 @@
DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.mm in Sources */,
DA87A99E1DC9DC2100810D09 /* MGLPredicateTests.mm in Sources */,
DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */,
+ CA0B3C092329FB4800E4B493 /* MGLOfflinePackTests.mm in Sources */,
170A82C4201FB6EC00943087 /* MGLHeatmapColorTests.mm in Sources */,
4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.mm in Sources */,
@@ -1760,7 +1767,6 @@
DAA999011E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm in Sources */,
DA29875A1E1A4290002299F5 /* MGLDocumentationExampleTests.swift in Sources */,
07BA4CAC1EE21887004528F5 /* MGLImageSourceTests.m in Sources */,
- DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */,
DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.mm in Sources */,
DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.mm in Sources */,
CA9461A620884CCB0015EB12 /* MGLAnnotationTests.m in Sources */,