diff options
author | Julian Rex <julian.rex@mapbox.com> | 2019-09-05 18:21:06 -0400 |
---|---|---|
committer | Julian Rex <julian.rex@mapbox.com> | 2019-09-18 16:50:25 -0400 |
commit | 30f2de6c2010c4991825f529b519b8669d340e7a (patch) | |
tree | 64195e3305dfb2a4fd741fbef3992c50d7b8d30d | |
parent | 047fda889b284ce4ab51b8178be0213c2e693274 (diff) | |
download | qtlocation-mapboxgl-30f2de6c2010c4991825f529b519b8669d340e7a.tar.gz |
[ios] Add tests for #15536
-rw-r--r-- | platform/darwin/test/MGLOfflineStorageTests.mm | 150 | ||||
-rw-r--r-- | platform/ios/ios.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | platform/ios/test/MGLTestAssertionHandler.h | 17 | ||||
-rw-r--r-- | platform/ios/test/MGLTestAssertionHandler.m | 41 |
4 files changed, 137 insertions, 77 deletions
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm index 398877e452..0138d911bb 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 @@ -310,7 +311,52 @@ 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)internalAddPacksForBounds:(dispatch_block_t)block { +- (void)testRemovePackTwiceInSuccession { + + [self addPackIfNeeded]; + + 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]; + [[[NSThread currentThread] threadDictionary] setValue:[[MGLTestAssertionHandler alloc] init] 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."); +} + +- (void)addPackIfNeeded { + XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"]; + + [self addPacks:1 completion:^{ + [expectation fulfill]; + }]; + [self waitForExpectations:@[expectation] timeout:1.0]; +} + +- (void)addPacks:(NSInteger)count completion:(dispatch_block_t)block { NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8]; MGLCoordinateBounds bounds[] = { @@ -320,10 +366,15 @@ {{37.7, -122.5}, {37.9, -122.4}} // SF }; - int count = sizeof(bounds)/sizeof(bounds[0]); + 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) @@ -335,91 +386,28 @@ XCTAssertNotNil(pack); XCTAssertNil(error); - if(block) - block(); - }]; - } -} - - -- (void)testRemovePacks1 { - NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; - - if (countOfPacks < 4) { - XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"]; - expectation.expectedFulfillmentCount = 4; - - [self internalAddPacksForBounds:^{ - [expectation fulfill]; + dispatch_group_leave(group); }]; - [self waitForExpectations:@[expectation] timeout:10.0]; } - countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; - XCTAssert(countOfPacks > 0); - - // Now delete - XCTestExpectation *expectation = [self expectationWithDescription:@"all packs removed"]; - expectation.expectedFulfillmentCount = countOfPacks; - - NSArray *packs = [MGLOfflineStorage sharedOfflineStorage].packs; - XCTAssertNotNil(packs); - - 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) { - [[MGLOfflineStorage sharedOfflineStorage] removePack:pack - withCompletionHandler:^(NSError * _Nullable error) { - [expectation fulfill]; - }]; + if (block) { + dispatch_group_notify(group, dispatch_get_main_queue(), block); } - - [self waitForExpectations:@[expectation] timeout:60.0]; - - countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; - XCTAssertEqual(countOfPacks, 0); - - - - // so on `keyPath` `packs` change (`NSKeyValueChange.settings`) -// we dispatch to a `SerialQueue` and remove the pack one by one and wait for the first one to be completed before proceeding to reduce the load on the Database access. -// serialQueue.async { [weak self] in -// guard let packs = storage.packs else { -// return [] -// } -// let validPacks = packs.filter { $0.state != .invalid } -// -// for pack in validPacks { -// let packGroup = DispatchGroup() -// packGroup.enter() -// storage.removePack(pack) { [weak self] (error) in -// packGroup.leave() -// } -// // Wait until the pack completion handler is executed -// // Marking the pack as removed for us -// packGroup.wait() -// } -// } } - -- (void)testRemovePacks { +// Test to explore https://github.com/mapbox/mapbox-gl-native/issues/15536 +- (void)testRemovePacksOnBackgroundQueueWhileReloading { NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; if (countOfPacks < 4) { XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"]; - expectation.expectedFulfillmentCount = 4; - [self internalAddPacksForBounds:^{ + [self addPacks:4 completion:^{ [expectation fulfill]; }]; [self waitForExpectations:@[expectation] timeout:10.0]; - - } + countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; XCTAssert(countOfPacks > 0); @@ -431,9 +419,14 @@ MGLOfflineStorage *storage = [MGLOfflineStorage sharedOfflineStorage]; - [self internalAddPacksForBounds:nil]; + [storage reloadPacks]; dispatch_async(queue, ^{ + + NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler]; + [[[NSThread currentThread] threadDictionary] setValue:[[MGLTestAssertionHandler alloc] init] forKey:NSAssertionHandlerKey]; + + NSArray *packs = storage.packs; if (!packs) { @@ -448,14 +441,17 @@ for (MGLOfflinePack *pack in validPacks) { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); +// [storage removePack:pack withCompletionHandler:nil]; [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]; diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 9ac5d564fe..a138e4ef06 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -523,6 +523,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 */; }; @@ -1211,6 +1212,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; path = MGLTestAssertionHandler.h; sourceTree = "<group>"; }; + CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = 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>"; }; @@ -1758,6 +1761,8 @@ 4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */, A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */, A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */, + CAAA65D72321BBA900F08A39 /* MGLTestAssertionHandler.h */, + CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */, ); name = "Test Helpers"; sourceTree = "<group>"; @@ -3264,6 +3269,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 */, diff --git a/platform/ios/test/MGLTestAssertionHandler.h b/platform/ios/test/MGLTestAssertionHandler.h new file mode 100644 index 0000000000..18ef67a407 --- /dev/null +++ b/platform/ios/test/MGLTestAssertionHandler.h @@ -0,0 +1,17 @@ +// +// MGLTestAssertionHandler.h +// test +// +// Created by Julian Rex on 9/5/19. +// Copyright © 2019 Mapbox. All rights reserved. +// + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLTestAssertionHandler : NSAssertionHandler + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/test/MGLTestAssertionHandler.m b/platform/ios/test/MGLTestAssertionHandler.m new file mode 100644 index 0000000000..b187a993ba --- /dev/null +++ b/platform/ios/test/MGLTestAssertionHandler.m @@ -0,0 +1,41 @@ +#import "MGLTestAssertionHandler.h" + +@implementation MGLTestAssertionHandler + +- (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); + + NSLog(@"NSAssert failure: Method `%@` (%@:%lu) for %@: %@", + NSStringFromSelector(selector), + fileName, + line, + object, + 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); + + NSLog(@"NSCAssert failure: Function `%@` (%@:%lu): %@", + functionName, + fileName, + line, + description); +} +@end + |