[ios, macos] Fix MGLOfflinePack invalidate crash (#15582)

This commit is contained in:
Julian Rex
2019-09-18 18:13:07 -04:00
committed by GitHub
parent 7bca176bea
commit 2b08c1d7bf
12 changed files with 354 additions and 14 deletions

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 */,

View File

@@ -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

View File

@@ -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 */,