[ios, macos] Raise exceptions for empty expression stops dictionaries (#9539)
This commit is contained in:
@@ -1258,9 +1258,15 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
|
||||
NSArray *controlPoints = [self.arguments[curveTypeIndex + 1].collection mgl_jsonExpressionObject];
|
||||
[interpolationArray addObjectsFromArray:controlPoints];
|
||||
}
|
||||
|
||||
NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[curveTypeIndex + 2].constantValue;
|
||||
|
||||
if (stops.count == 0) {
|
||||
[NSException raise:NSInvalidArgumentException format:@"‘stops‘ dictionary argument to ‘%@’ function must not be empty.", self.function];
|
||||
}
|
||||
|
||||
NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"interpolate", interpolationArray, nil];
|
||||
[expressionObject addObject:(isAftermarketFunction ? self.arguments.firstObject : self.operand).mgl_jsonExpressionObject];
|
||||
NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[curveTypeIndex + 2].constantValue;
|
||||
for (NSNumber *key in [stops.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
|
||||
[expressionObject addObject:key];
|
||||
[expressionObject addObject:[stops[key] mgl_jsonExpressionObject]];
|
||||
@@ -1272,8 +1278,14 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
|
||||
BOOL isAftermarketFunction = [self.function isEqualToString:@"mgl_step:from:stops:"];
|
||||
NSUInteger minimumIndex = isAftermarketFunction ? 1 : 0;
|
||||
id minimum = self.arguments[minimumIndex].mgl_jsonExpressionObject;
|
||||
NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"step", (isAftermarketFunction ? self.arguments.firstObject : self.operand).mgl_jsonExpressionObject, minimum, nil];
|
||||
NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[minimumIndex + 1].constantValue;
|
||||
|
||||
if (stops.count == 0) {
|
||||
[NSException raise:NSInvalidArgumentException format:@"‘stops‘ dictionary argument to ‘%@’ function must not be empty.", self.function];
|
||||
}
|
||||
|
||||
NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"step", (isAftermarketFunction ? self.arguments.firstObject : self.operand).mgl_jsonExpressionObject, minimum, nil];
|
||||
|
||||
for (NSNumber *key in [stops.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
|
||||
[expressionObject addObject:key];
|
||||
[expressionObject addObject:[stops[key] mgl_jsonExpressionObject]];
|
||||
|
||||
@@ -710,6 +710,16 @@ using namespace std::string_literals;
|
||||
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
|
||||
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
|
||||
}
|
||||
{
|
||||
NSDictionary *stops = @{};
|
||||
NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(x, 'cubic-bezier', { 0.42, 0, 0.58, 1 }, %@)", stops];
|
||||
XCTAssertThrowsSpecificNamed(expression.mgl_jsonExpressionObject, NSException, NSInvalidArgumentException);
|
||||
}
|
||||
{
|
||||
NSDictionary *stops = @{};
|
||||
NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, 11, %@)", stops];
|
||||
XCTAssertThrowsSpecificNamed(expression.mgl_jsonExpressionObject, NSException, NSInvalidArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testMatchExpressionObject {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#import "MGLMapViewIntegrationTest.h"
|
||||
|
||||
@interface MGLStyleLayerIntegrationTests : MGLMapViewIntegrationTest
|
||||
@end
|
||||
|
||||
@implementation MGLStyleLayerIntegrationTests
|
||||
|
||||
- (MGLCircleStyleLayer*)setupCircleStyleLayer {
|
||||
// Adapted from https://www.mapbox.com/ios-sdk/examples/dds-circle-layer/
|
||||
|
||||
// "mapbox://examples.2uf7qges" is a map ID referencing a tileset. For more
|
||||
// more information, see mapbox.com/help/define-map-id/
|
||||
MGLSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"trees" configurationURL:[NSURL URLWithString:@"mapbox://examples.2uf7qges"]];
|
||||
[self.mapView.style addSource:source];
|
||||
|
||||
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier: @"tree-style" source:source];
|
||||
|
||||
// The source name from the source's TileJSON metadata: mapbox.com/api-documentation/#retrieve-tilejson-metadata
|
||||
layer.sourceLayerIdentifier = @"yoshino-trees-a0puw5";
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
- (void)testForInterpolatingExpressionRenderCrashWithEmptyStops {
|
||||
// Tests: https://github.com/mapbox/mapbox-gl-native/issues/9539
|
||||
// Adapted from https://www.mapbox.com/ios-sdk/examples/dds-circle-layer/
|
||||
self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039);
|
||||
self.mapView.zoomLevel = 10.5;
|
||||
|
||||
MGLCircleStyleLayer *layer = [self setupCircleStyleLayer];
|
||||
|
||||
NSExpression *interpExpression = [NSExpression mgl_expressionForInterpolatingExpression:NSExpression.zoomLevelVariableExpression
|
||||
withCurveType:MGLExpressionInterpolationModeLinear
|
||||
parameters:nil
|
||||
stops:[NSExpression expressionForConstantValue:@{}]];
|
||||
|
||||
XCTAssertThrowsSpecificNamed((layer.circleColor = interpExpression), NSException, NSInvalidArgumentException);
|
||||
|
||||
[self.mapView.style addLayer:layer];
|
||||
[self waitForMapViewToBeRenderedWithTimeout:1.0];
|
||||
}
|
||||
|
||||
- (void)testForSteppingExpressionRenderCrashWithEmptyStops {
|
||||
// Tests: https://github.com/mapbox/mapbox-gl-native/issues/9539
|
||||
// Adapted from https://www.mapbox.com/ios-sdk/examples/dds-circle-layer/
|
||||
self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039);
|
||||
self.mapView.zoomLevel = 10.5;
|
||||
|
||||
MGLCircleStyleLayer *layer = [self setupCircleStyleLayer];
|
||||
|
||||
NSExpression *steppingExpression = [NSExpression mgl_expressionForSteppingExpression:NSExpression.zoomLevelVariableExpression
|
||||
fromExpression:[NSExpression expressionForConstantValue:[UIColor greenColor]]
|
||||
stops:[NSExpression expressionForConstantValue:@{}]];
|
||||
|
||||
XCTAssertThrowsSpecificNamed((layer.circleColor = steppingExpression), NSException, NSInvalidArgumentException);
|
||||
|
||||
[self.mapView.style addLayer:layer];
|
||||
[self waitForMapViewToBeRenderedWithTimeout:1.0];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -362,6 +362,7 @@
|
||||
AC518E03201BB56000EBC820 /* MGLTelemetryConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */; };
|
||||
AC518E04201BB56100EBC820 /* MGLTelemetryConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */; };
|
||||
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */; };
|
||||
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */; };
|
||||
CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CAA69DA4206DCD0E007279CD /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; };
|
||||
@@ -993,6 +994,7 @@
|
||||
AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTelemetryConfig.m; sourceTree = "<group>"; };
|
||||
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewIntegrationTest.m; sourceTree = "<group>"; };
|
||||
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLMapViewIntegrationTest.h; sourceTree = "<group>"; };
|
||||
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerIntegrationTests.m; sourceTree = "<group>"; };
|
||||
CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = "<group>"; };
|
||||
DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; };
|
||||
DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; };
|
||||
@@ -1345,6 +1347,7 @@
|
||||
16376B0B1FFD9DAF0000563E /* Info.plist */,
|
||||
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */,
|
||||
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */,
|
||||
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */,
|
||||
);
|
||||
path = "Integration Tests";
|
||||
sourceTree = "<group>";
|
||||
@@ -2793,6 +2796,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */,
|
||||
16376B0A1FFD9DAF0000563E /* MBGLIntegrationTests.m in Sources */,
|
||||
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user