diff options
Diffstat (limited to 'platform/darwin/test')
30 files changed, 5016 insertions, 1189 deletions
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.m b/platform/darwin/test/MGLBackgroundStyleLayerTests.m deleted file mode 100644 index 934021d6b8..0000000000 --- a/platform/darwin/test/MGLBackgroundStyleLayerTests.m +++ /dev/null @@ -1,44 +0,0 @@ -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGLBackgroundLayerTests : MGLStyleLayerTests -@end - -@implementation MGLBackgroundLayerTests - -+ (NSString *)layerType { - return @"background"; -} - -- (void)testBackgroundLayer { - MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"]; - [self.mapView.style addLayer:layer]; - - layer.backgroundColor = [MGLRuntimeStylingHelper testColor]; - layer.backgroundOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.backgroundPattern = [MGLRuntimeStylingHelper testString]; - - MGLBackgroundStyleLayer *gLayer = (MGLBackgroundStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGLBackgroundStyleLayer class]]); - XCTAssertEqualObjects(gLayer.backgroundColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.backgroundOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testString]); - - layer.backgroundColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.backgroundOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.backgroundPattern = [MGLRuntimeStylingHelper testStringFunction]; - - XCTAssertEqualObjects(gLayer.backgroundColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.backgroundOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.backgroundPattern, [MGLRuntimeStylingHelper testStringFunction]); -} - -- (void)testPropertyNames { - [self testPropertyName:@"background-color" isBoolean:NO]; - [self testPropertyName:@"background-opacity" isBoolean:NO]; - [self testPropertyName:@"background-pattern" isBoolean:NO]; -} - -@end diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm new file mode 100644 index 0000000000..60a332a5e7 --- /dev/null +++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm @@ -0,0 +1,134 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/background_layer.hpp> + +@interface MGLBackgroundLayerTests : MGLStyleLayerTests +@end + +@implementation MGLBackgroundLayerTests + ++ (NSString *)layerType { + return @"background"; +} + +- (void)testProperties { + MGLBackgroundStyleLayer *layer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"layerID"]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::BackgroundLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::BackgroundLayer>(); + + // background-color + { + XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(), + @"background-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.backgroundColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.backgroundColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue, + @"Setting backgroundColor to a constant value should update background-color."); + XCTAssertEqualObjects(layer.backgroundColor, styleValue, + @"backgroundColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.backgroundColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue, + @"Setting backgroundColor to a function should update background-color."); + XCTAssertEqualObjects(layer.backgroundColor, styleValue, + @"backgroundColor should round-trip functions."); + + layer.backgroundColor = nil; + XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(), + @"Unsetting backgroundColor should return background-color to the default value."); + XCTAssertEqualObjects(layer.backgroundColor, defaultStyleValue, + @"backgroundColor should return the default value after being unset."); + } + + // background-opacity + { + XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(), + @"background-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.backgroundOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.backgroundOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue, + @"Setting backgroundOpacity to a constant value should update background-opacity."); + XCTAssertEqualObjects(layer.backgroundOpacity, styleValue, + @"backgroundOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.backgroundOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue, + @"Setting backgroundOpacity to a function should update background-opacity."); + XCTAssertEqualObjects(layer.backgroundOpacity, styleValue, + @"backgroundOpacity should round-trip functions."); + + layer.backgroundOpacity = nil; + XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(), + @"Unsetting backgroundOpacity should return background-opacity to the default value."); + XCTAssertEqualObjects(layer.backgroundOpacity, defaultStyleValue, + @"backgroundOpacity should return the default value after being unset."); + } + + // background-pattern + { + XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(), + @"background-pattern should be unset initially."); + MGLStyleValue<NSString *> *defaultStyleValue = layer.backgroundPattern; + + MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Background Pattern"]; + layer.backgroundPattern = styleValue; + mbgl::style::PropertyValue<std::string> propertyValue = { "Background Pattern" }; + XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue, + @"Setting backgroundPattern to a constant value should update background-pattern."); + XCTAssertEqualObjects(layer.backgroundPattern, styleValue, + @"backgroundPattern should round-trip constant values."); + + styleValue = [MGLStyleValue<NSString *> valueWithStops:@{ + @18: styleValue, + }]; + layer.backgroundPattern = styleValue; + propertyValue = { mbgl::style::Function<std::string> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue, + @"Setting backgroundPattern to a function should update background-pattern."); + XCTAssertEqualObjects(layer.backgroundPattern, styleValue, + @"backgroundPattern should round-trip functions."); + + layer.backgroundPattern = nil; + XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(), + @"Unsetting backgroundPattern should return background-pattern to the default value."); + XCTAssertEqualObjects(layer.backgroundPattern, defaultStyleValue, + @"backgroundPattern should return the default value after being unset."); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"background-color" isBoolean:NO]; + [self testPropertyName:@"background-opacity" isBoolean:NO]; + [self testPropertyName:@"background-pattern" isBoolean:NO]; +} + +@end diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.m b/platform/darwin/test/MGLCircleStyleLayerTests.m deleted file mode 100644 index ce17d93557..0000000000 --- a/platform/darwin/test/MGLCircleStyleLayerTests.m +++ /dev/null @@ -1,85 +0,0 @@ -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGLCircleLayerTests : MGLStyleLayerTests -@end - -@implementation MGLCircleLayerTests - -+ (NSString *)layerType { - return @"circle"; -} - -- (void)testCircleLayer { - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; - [self.mapView.style addLayer:layer]; - - layer.circleBlur = [MGLRuntimeStylingHelper testNumber]; - layer.circleColor = [MGLRuntimeStylingHelper testColor]; - layer.circleOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.circlePitchScale = [MGLRuntimeStylingHelper testEnum:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]; - layer.circleRadius = [MGLRuntimeStylingHelper testNumber]; - layer.circleStrokeColor = [MGLRuntimeStylingHelper testColor]; - layer.circleStrokeOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.circleStrokeWidth = [MGLRuntimeStylingHelper testNumber]; - layer.circleTranslate = [MGLRuntimeStylingHelper testOffset]; - layer.circleTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]; - - MGLCircleStyleLayer *gLayer = (MGLCircleStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGLCircleStyleLayer class]]); - XCTAssertEqualObjects(gLayer.circleBlur, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.circleColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.circleOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssert([gLayer.circlePitchScale isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.circlePitchScale, [MGLRuntimeStylingHelper testEnum:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]); - XCTAssertEqualObjects(gLayer.circleRadius, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.circleStrokeColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.circleStrokeOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.circleStrokeWidth, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.circleTranslate, [MGLRuntimeStylingHelper testOffset]); - XCTAssert([gLayer.circleTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]); - - layer.circleBlur = [MGLRuntimeStylingHelper testNumberFunction]; - layer.circleColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.circleOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.circlePitchScale = [MGLRuntimeStylingHelper testEnumFunction:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]; - layer.circleRadius = [MGLRuntimeStylingHelper testNumberFunction]; - layer.circleStrokeColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.circleStrokeOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.circleStrokeWidth = [MGLRuntimeStylingHelper testNumberFunction]; - layer.circleTranslate = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.circleTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]; - - XCTAssertEqualObjects(gLayer.circleBlur, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.circleColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.circleOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.circlePitchScale, [MGLRuntimeStylingHelper testEnumFunction:MGLCirclePitchScaleViewport type:@encode(MGLCirclePitchScale)]); - XCTAssertEqualObjects(gLayer.circleRadius, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.circleStrokeColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.circleStrokeOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.circleStrokeWidth, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.circleTranslate, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.circleTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLCircleTranslateAnchorViewport type:@encode(MGLCircleTranslateAnchor)]); -} - -- (void)testPropertyNames { - [self testPropertyName:@"circle-blur" isBoolean:NO]; - [self testPropertyName:@"circle-color" isBoolean:NO]; - [self testPropertyName:@"circle-opacity" isBoolean:NO]; - [self testPropertyName:@"circle-pitch-scale" isBoolean:NO]; - [self testPropertyName:@"circle-radius" isBoolean:NO]; - [self testPropertyName:@"circle-stroke-color" isBoolean:NO]; - [self testPropertyName:@"circle-stroke-opacity" isBoolean:NO]; - [self testPropertyName:@"circle-stroke-width" isBoolean:NO]; - [self testPropertyName:@"circle-translate" isBoolean:NO]; - [self testPropertyName:@"circle-translate-anchor" isBoolean:NO]; -} - -@end diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm new file mode 100644 index 0000000000..35e29b31d5 --- /dev/null +++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm @@ -0,0 +1,413 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/circle_layer.hpp> + +@interface MGLCircleLayerTests : MGLStyleLayerTests +@end + +@implementation MGLCircleLayerTests + ++ (NSString *)layerType { + return @"circle"; +} + +- (void)testPredicates { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertNil(layer.sourceLayerIdentifier); + layer.sourceLayerIdentifier = @"layerID"; + XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID"); + layer.sourceLayerIdentifier = nil; + XCTAssertNil(layer.sourceLayerIdentifier); + + XCTAssertNil(layer.predicate); + layer.predicate = [NSPredicate predicateWithValue:NO]; + XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]); + layer.predicate = nil; + XCTAssertNil(layer.predicate); +} + +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::CircleLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::CircleLayer>(); + + // circle-blur + { + XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(), + @"circle-blur should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleBlur; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.circleBlur = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue, + @"Setting circleBlur to a constant value should update circle-blur."); + XCTAssertEqualObjects(layer.circleBlur, styleValue, + @"circleBlur should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleBlur = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue, + @"Setting circleBlur to a function should update circle-blur."); + XCTAssertEqualObjects(layer.circleBlur, styleValue, + @"circleBlur should round-trip functions."); + + layer.circleBlur = nil; + XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(), + @"Unsetting circleBlur should return circle-blur to the default value."); + XCTAssertEqualObjects(layer.circleBlur, defaultStyleValue, + @"circleBlur should return the default value after being unset."); + } + + // circle-color + { + XCTAssertTrue(rawLayer->getCircleColor().isUndefined(), + @"circle-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.circleColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getCircleColor(), propertyValue, + @"Setting circleColor to a constant value should update circle-color."); + XCTAssertEqualObjects(layer.circleColor, styleValue, + @"circleColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleColor(), propertyValue, + @"Setting circleColor to a function should update circle-color."); + XCTAssertEqualObjects(layer.circleColor, styleValue, + @"circleColor should round-trip functions."); + + layer.circleColor = nil; + XCTAssertTrue(rawLayer->getCircleColor().isUndefined(), + @"Unsetting circleColor should return circle-color to the default value."); + XCTAssertEqualObjects(layer.circleColor, defaultStyleValue, + @"circleColor should return the default value after being unset."); + } + + // circle-opacity + { + XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(), + @"circle-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.circleOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue, + @"Setting circleOpacity to a constant value should update circle-opacity."); + XCTAssertEqualObjects(layer.circleOpacity, styleValue, + @"circleOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue, + @"Setting circleOpacity to a function should update circle-opacity."); + XCTAssertEqualObjects(layer.circleOpacity, styleValue, + @"circleOpacity should round-trip functions."); + + layer.circleOpacity = nil; + XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(), + @"Unsetting circleOpacity should return circle-opacity to the default value."); + XCTAssertEqualObjects(layer.circleOpacity, defaultStyleValue, + @"circleOpacity should return the default value after being unset."); + } + + // circle-radius + { + XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(), + @"circle-radius should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleRadius; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.circleRadius = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue, + @"Setting circleRadius to a constant value should update circle-radius."); + XCTAssertEqualObjects(layer.circleRadius, styleValue, + @"circleRadius should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleRadius = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue, + @"Setting circleRadius to a function should update circle-radius."); + XCTAssertEqualObjects(layer.circleRadius, styleValue, + @"circleRadius should round-trip functions."); + + layer.circleRadius = nil; + XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(), + @"Unsetting circleRadius should return circle-radius to the default value."); + XCTAssertEqualObjects(layer.circleRadius, defaultStyleValue, + @"circleRadius should return the default value after being unset."); + } + + // circle-pitch-scale + { + XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(), + @"circle-pitch-scale should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleScaleAlignment; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]]; + layer.circleScaleAlignment = styleValue; + mbgl::style::PropertyValue<mbgl::style::CirclePitchScaleType> propertyValue = { mbgl::style::CirclePitchScaleType::Viewport }; + XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue, + @"Setting circleScaleAlignment to a constant value should update circle-pitch-scale."); + XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue, + @"circleScaleAlignment should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleScaleAlignment = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::CirclePitchScaleType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue, + @"Setting circleScaleAlignment to a function should update circle-pitch-scale."); + XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue, + @"circleScaleAlignment should round-trip functions."); + + layer.circleScaleAlignment = nil; + XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(), + @"Unsetting circleScaleAlignment should return circle-pitch-scale to the default value."); + XCTAssertEqualObjects(layer.circleScaleAlignment, defaultStyleValue, + @"circleScaleAlignment should return the default value after being unset."); + } + + // circle-stroke-color + { + XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(), + @"circle-stroke-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleStrokeColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.circleStrokeColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue, + @"Setting circleStrokeColor to a constant value should update circle-stroke-color."); + XCTAssertEqualObjects(layer.circleStrokeColor, styleValue, + @"circleStrokeColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleStrokeColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue, + @"Setting circleStrokeColor to a function should update circle-stroke-color."); + XCTAssertEqualObjects(layer.circleStrokeColor, styleValue, + @"circleStrokeColor should round-trip functions."); + + layer.circleStrokeColor = nil; + XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(), + @"Unsetting circleStrokeColor should return circle-stroke-color to the default value."); + XCTAssertEqualObjects(layer.circleStrokeColor, defaultStyleValue, + @"circleStrokeColor should return the default value after being unset."); + } + + // circle-stroke-opacity + { + XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(), + @"circle-stroke-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.circleStrokeOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue, + @"Setting circleStrokeOpacity to a constant value should update circle-stroke-opacity."); + XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue, + @"circleStrokeOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleStrokeOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue, + @"Setting circleStrokeOpacity to a function should update circle-stroke-opacity."); + XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue, + @"circleStrokeOpacity should round-trip functions."); + + layer.circleStrokeOpacity = nil; + XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(), + @"Unsetting circleStrokeOpacity should return circle-stroke-opacity to the default value."); + XCTAssertEqualObjects(layer.circleStrokeOpacity, defaultStyleValue, + @"circleStrokeOpacity should return the default value after being unset."); + } + + // circle-stroke-width + { + XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(), + @"circle-stroke-width should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeWidth; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.circleStrokeWidth = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue, + @"Setting circleStrokeWidth to a constant value should update circle-stroke-width."); + XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue, + @"circleStrokeWidth should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleStrokeWidth = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue, + @"Setting circleStrokeWidth to a function should update circle-stroke-width."); + XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue, + @"circleStrokeWidth should round-trip functions."); + + layer.circleStrokeWidth = nil; + XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(), + @"Unsetting circleStrokeWidth should return circle-stroke-width to the default value."); + XCTAssertEqualObjects(layer.circleStrokeWidth, defaultStyleValue, + @"circleStrokeWidth should return the default value after being unset."); + } + + // circle-translate + { + XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(), + @"circle-translate should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslation; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.circleTranslation = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue, + @"Setting circleTranslation to a constant value should update circle-translate."); + XCTAssertEqualObjects(layer.circleTranslation, styleValue, + @"circleTranslation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleTranslation = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue, + @"Setting circleTranslation to a function should update circle-translate."); + XCTAssertEqualObjects(layer.circleTranslation, styleValue, + @"circleTranslation should round-trip functions."); + + layer.circleTranslation = nil; + XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(), + @"Unsetting circleTranslation should return circle-translate to the default value."); + XCTAssertEqualObjects(layer.circleTranslation, defaultStyleValue, + @"circleTranslation should return the default value after being unset."); + } + + // circle-translate-anchor + { + XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(), + @"circle-translate-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslationAnchor; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]]; + layer.circleTranslationAnchor = styleValue; + mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; + XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue, + @"Setting circleTranslationAnchor to a constant value should update circle-translate-anchor."); + XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue, + @"circleTranslationAnchor should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.circleTranslationAnchor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue, + @"Setting circleTranslationAnchor to a function should update circle-translate-anchor."); + XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue, + @"circleTranslationAnchor should round-trip functions."); + + layer.circleTranslationAnchor = nil; + XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(), + @"Unsetting circleTranslationAnchor should return circle-translate-anchor to the default value."); + XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultStyleValue, + @"circleTranslationAnchor should return the default value after being unset."); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"circle-blur" isBoolean:NO]; + [self testPropertyName:@"circle-color" isBoolean:NO]; + [self testPropertyName:@"circle-opacity" isBoolean:NO]; + [self testPropertyName:@"circle-radius" isBoolean:NO]; + [self testPropertyName:@"circle-scale-alignment" isBoolean:NO]; + [self testPropertyName:@"circle-stroke-color" isBoolean:NO]; + [self testPropertyName:@"circle-stroke-opacity" isBoolean:NO]; + [self testPropertyName:@"circle-stroke-width" isBoolean:NO]; + [self testPropertyName:@"circle-translation" isBoolean:NO]; + [self testPropertyName:@"circle-translation-anchor" isBoolean:NO]; +} + +- (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentMap].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentMap); + XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentViewport); + XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorMap].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorMap); + XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorViewport); +} + +@end diff --git a/platform/darwin/test/MGLCodingTests.m b/platform/darwin/test/MGLCodingTests.m new file mode 100644 index 0000000000..b9b299d50f --- /dev/null +++ b/platform/darwin/test/MGLCodingTests.m @@ -0,0 +1,469 @@ +#import <Mapbox/Mapbox.h> +#import <XCTest/XCTest.h> + +#if TARGET_OS_IPHONE +#import "MGLUserLocation_Private.h" +#endif + +@interface MGLCodingTests : XCTestCase +@end + +@implementation MGLCodingTests + +- (NSString *)temporaryFilePathForClass:(Class)clazz { + return [NSTemporaryDirectory() stringByAppendingPathComponent:NSStringFromClass(clazz)]; +} + +- (void)testPointAnnotation { + MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init]; + annotation.coordinate = CLLocationCoordinate2DMake(0.5, 0.5); + annotation.title = @"title"; + annotation.subtitle = @"subtitle"; + + NSString *filePath = [self temporaryFilePathForClass:MGLPointAnnotation.class]; + [NSKeyedArchiver archiveRootObject:annotation toFile:filePath]; + MGLPointAnnotation *unarchivedAnnotation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(annotation, unarchivedAnnotation); +} + +- (void)testPointFeature { + MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init]; + pointFeature.title = @"title"; + pointFeature.subtitle = @"subtitle"; + pointFeature.identifier = @(123); + pointFeature.attributes = @{@"bbox": @[@1, @2, @3, @4]}; + + NSString *filePath = [self temporaryFilePathForClass:MGLPointFeature.class]; + [NSKeyedArchiver archiveRootObject:pointFeature toFile:filePath]; + MGLPointFeature *unarchivedPointFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(pointFeature, unarchivedPointFeature); +} + +- (void)testPolyline { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0.129631234123, 1.7812739312551), + CLLocationCoordinate2DMake(2.532083092342, 3.5216418292392) + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates]; + polyline.title = @"title"; + polyline.subtitle = @"subtitle"; + + NSString *filePath = [self temporaryFilePathForClass:[MGLPolyline class]]; + [NSKeyedArchiver archiveRootObject:polyline toFile:filePath]; + MGLPolyline *unarchivedPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(polyline, unarchivedPolyline); + + CLLocationCoordinate2D otherCoordinates[] = { + CLLocationCoordinate2DMake(-1, -2) + }; + + [unarchivedPolyline replaceCoordinatesInRange:NSMakeRange(0, 1) withCoordinates:otherCoordinates]; + + XCTAssertNotEqualObjects(polyline, unarchivedPolyline); +} + +- (void)testPolygon { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0.664482398, 1.8865675), + CLLocationCoordinate2DMake(2.13224687, 3.9984632) + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates]; + polygon.title = nil; + polygon.subtitle = @"subtitle"; + + NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]]; + [NSKeyedArchiver archiveRootObject:polygon toFile:filePath]; + + MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(polygon, unarchivedPolygon); +} + +- (void)testPolygonWithInteriorPolygons { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 20) + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + CLLocationCoordinate2D interiorCoordinates[] = { + CLLocationCoordinate2DMake(4, 4), + CLLocationCoordinate2DMake(6, 6) + }; + + NSUInteger numberOfInteriorCoordinates = sizeof(interiorCoordinates) / sizeof(CLLocationCoordinate2D); + + MGLPolygon *interiorPolygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:numberOfInteriorCoordinates]; + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates interiorPolygons:@[interiorPolygon]]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]]; + [NSKeyedArchiver archiveRootObject:polygon toFile:filePath]; + + MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(polygon, unarchivedPolygon); +} + +- (void)testPolylineFeature { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 20) + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates]; + polylineFeature.attributes = @{@"bbox": @[@0, @1, @2, @3]}; + polylineFeature.identifier = @"identifier"; + + NSString *filePath = [self temporaryFilePathForClass:[MGLPolylineFeature class]]; + [NSKeyedArchiver archiveRootObject:polylineFeature toFile:filePath]; + + MGLPolylineFeature *unarchivedPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(polylineFeature, unarchivedPolylineFeature); + + unarchivedPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]}; + + XCTAssertNotEqualObjects(polylineFeature, unarchivedPolylineFeature); +} + +- (void)testPolygonFeature { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 20) + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLPolygonFeature class]]; + [NSKeyedArchiver archiveRootObject:polygonFeature toFile:filePath]; + + MGLPolygonFeature *unarchivedPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(polygonFeature, unarchivedPolygonFeature); + + unarchivedPolygonFeature.identifier = @"test"; + + XCTAssertNotEqualObjects(polygonFeature, unarchivedPolygonFeature); +} + +- (void)testPointCollection { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 11), + CLLocationCoordinate2DMake(20, 21), + CLLocationCoordinate2DMake(30, 31), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + MGLPointCollection *pointCollection = [MGLPointCollection pointCollectionWithCoordinates:coordinates count:numberOfCoordinates]; + NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollection class]]; + [NSKeyedArchiver archiveRootObject:pointCollection toFile:filePath]; + + MGLPointCollection *unarchivedPointCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(pointCollection, unarchivedPointCollection); +} + +- (void)testPointCollectionFeature { + NSMutableArray *features = [NSMutableArray array]; + for (NSUInteger i = 0; i < 100; i++) { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + feature.coordinate = CLLocationCoordinate2DMake(arc4random() % 90, arc4random() % 180); + [features addObject:feature]; + } + + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 11), + CLLocationCoordinate2DMake(20, 21), + CLLocationCoordinate2DMake(30, 31), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + MGLPointCollectionFeature *collection = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:numberOfCoordinates]; + collection.identifier = @"identifier"; + collection.attributes = @{@"bbox": @[@1, @2, @3, @4]}; + + NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollectionFeature class]]; + [NSKeyedArchiver archiveRootObject:collection toFile:filePath]; + + MGLPointCollectionFeature *unarchivedCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(collection, unarchivedCollection); + + unarchivedCollection.identifier = @"newIdentifier"; + + XCTAssertNotEqualObjects(collection, unarchivedCollection); +} + +- (void)testMultiPolyline { + + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 11), + CLLocationCoordinate2DMake(20, 21), + CLLocationCoordinate2DMake(30, 31), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + NSMutableArray *polylines = [NSMutableArray array]; + + for (NSUInteger i = 0; i < 100; i++) { + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates]; + [polylines addObject:polyline]; + } + + MGLMultiPolyline *multiPolyline = [MGLMultiPolyline multiPolylineWithPolylines:polylines]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolyline class]]; + [NSKeyedArchiver archiveRootObject:multiPolyline toFile:filePath]; + + MGLMultiPolyline *unarchivedMultiPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + MGLMultiPolyline *anotherMultipolyline = [MGLMultiPolyline multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]]; + + XCTAssertEqualObjects(multiPolyline, unarchivedMultiPolyline); + XCTAssertNotEqualObjects(unarchivedMultiPolyline, anotherMultipolyline); +} + +- (void)testMultiPolygon { + + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(0, 1), + CLLocationCoordinate2DMake(10, 11), + CLLocationCoordinate2DMake(20, 21), + CLLocationCoordinate2DMake(30, 31), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + NSMutableArray *polygons = [NSMutableArray array]; + + for (NSUInteger i = 0; i < 100; i++) { + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates]; + [polygons addObject:polygon]; + } + + MGLMultiPolygon *multiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:polygons]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolygon class]]; + [NSKeyedArchiver archiveRootObject:multiPolygon toFile:filePath]; + + MGLMultiPolygon *unarchivedMultiPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + MGLMultiPolygon *anotherMultiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]]; + + XCTAssertEqualObjects(multiPolygon, unarchivedMultiPolygon); + XCTAssertNotEqualObjects(anotherMultiPolygon, unarchivedMultiPolygon); +} + +- (void)testShapeCollection { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(10.12315786, 11.23451186), + CLLocationCoordinate2DMake(20.91836515, 21.93689215), + CLLocationCoordinate2DMake(30.55697246, 31.33988123), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates]; + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates]; + + MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polyline, polygon]]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollection class]]; + [NSKeyedArchiver archiveRootObject:shapeCollection toFile:filePath]; + + MGLShapeCollection *unarchivedShapeCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + MGLShapeCollection *anotherShapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polygon]]; + + XCTAssertEqualObjects(shapeCollection, unarchivedShapeCollection); + XCTAssertNotEqualObjects(shapeCollection, anotherShapeCollection); +} + +- (void)testMultiPolylineFeature { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(10.12315786, 11.23451186), + CLLocationCoordinate2DMake(20.91836515, 21.93689215), + CLLocationCoordinate2DMake(30.55697246, 31.33988123), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + NSMutableArray *polylines = [NSMutableArray array]; + for (NSUInteger i = 0; i < 100; i++) { + MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates]; + polylineFeature.identifier = @(arc4random() % 100).stringValue; + [polylines addObject:polylineFeature]; + } + + MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines]; + multiPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]}; + + NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]]; + [NSKeyedArchiver archiveRootObject:multiPolylineFeature toFile:filePath]; + + MGLMultiPolylineFeature *unarchivedMultiPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + MGLMultiPolylineFeature *anotherMultiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]]; + + XCTAssertEqualObjects(multiPolylineFeature, unarchivedMultiPolylineFeature); + XCTAssertNotEqualObjects(unarchivedMultiPolylineFeature, anotherMultiPolylineFeature); +} + +- (void)testMultiPolygonFeature { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(10.12315786, 11.23451185), + CLLocationCoordinate2DMake(20.88471238, 21.93684215), + CLLocationCoordinate2DMake(30.15697236, 31.32988123), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + NSMutableArray *polygons = [NSMutableArray array]; + for (NSUInteger i = 0; i < 100; i++ ) { + MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates]; + polygonFeature.identifier = @(arc4random_uniform(100)).stringValue; + [polygons addObject:polygonFeature]; + } + + MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons]; + multiPolygonFeature.attributes = @{@"bbox": @[@(arc4random_uniform(100)), + @(arc4random_uniform(100)), + @(arc4random_uniform(100)), + @(arc4random_uniform(100))]}; + + NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]]; + [NSKeyedArchiver archiveRootObject:multiPolygonFeature toFile:filePath]; + + MGLMultiPolygonFeature *unarchivedMultiPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + MGLMultiPolygonFeature *anotherMultiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]]; + + XCTAssertEqualObjects(multiPolygonFeature, unarchivedMultiPolygonFeature); + XCTAssertNotEqualObjects(anotherMultiPolygonFeature, unarchivedMultiPolygonFeature); +} + +- (void)testShapeCollectionFeature { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(10.12315786, 11.23451186), + CLLocationCoordinate2DMake(20.91836515, 21.93689215), + CLLocationCoordinate2DMake(30.55697246, 31.33988123), + }; + + NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D); + + MGLPolylineFeature *polyline = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates]; + MGLPolygonFeature *polygon = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates]; + + MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polyline, polygon]]; + shapeCollectionFeature.identifier = @(arc4random_uniform(100)).stringValue; + shapeCollectionFeature.attributes = @{@"bbox":@[@(arc4random_uniform(100)), + @(arc4random_uniform(100)), + @(arc4random_uniform(100)), + @(arc4random_uniform(100))]}; + + NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollectionFeature class]]; + [NSKeyedArchiver archiveRootObject:shapeCollectionFeature toFile:filePath]; + + MGLShapeCollectionFeature *unarchivedShapeCollectionFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(shapeCollectionFeature, unarchivedShapeCollectionFeature); +} + +- (void)testAnnotationImage { +#if TARGET_OS_IPHONE + UIGraphicsBeginImageContext(CGSizeMake(10, 10)); + [[UIColor redColor] setFill]; + UIRectFill(CGRectMake(0, 0, 10, 10)); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); +#else + NSImage *image = [[NSImage alloc] initWithSize:CGSizeMake(10, 10)]; + [image lockFocus]; + [[NSColor redColor] drawSwatchInRect:CGRectMake(0, 0, 10, 10)]; + [image unlockFocus]; +#endif + + MGLAnnotationImage *annotationImage = [MGLAnnotationImage annotationImageWithImage:image reuseIdentifier:@(arc4random_uniform(100)).stringValue]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationImage class]]; + [NSKeyedArchiver archiveRootObject:annotationImage toFile:filePath]; + + MGLAnnotationImage *unarchivedAnnotationImage = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(annotationImage, unarchivedAnnotationImage); +} + +#if TARGET_OS_IPHONE +- (void)testAnnotationView { + MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithReuseIdentifier:@"id"]; + annotationView.enabled = NO; + annotationView.selected = YES; + annotationView.draggable = YES; + annotationView.centerOffset = CGVectorMake(10, 10); + annotationView.scalesWithViewingDistance = NO; + + NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationView class]]; + [NSKeyedArchiver archiveRootObject:annotationView toFile:filePath]; + + MGLAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled); + XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected); + XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable); + XCTAssertEqualObjects(NSStringFromCGVector(annotationView.centerOffset), NSStringFromCGVector(unarchivedAnnotationView.centerOffset)); + XCTAssertEqual(annotationView.scalesWithViewingDistance, unarchivedAnnotationView.scalesWithViewingDistance); +} +#endif + +#if TARGET_OS_IPHONE +- (void)testUserLocation { + MGLUserLocation *userLocation = [[MGLUserLocation alloc] init]; + userLocation.location = [[CLLocation alloc] initWithLatitude:1 longitude:1]; + + NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocation class]]; + [NSKeyedArchiver archiveRootObject:userLocation toFile:filePath]; + + MGLUserLocation *unarchivedUserLocation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqualObjects(userLocation, unarchivedUserLocation); + unarchivedUserLocation.location = [[CLLocation alloc] initWithLatitude:10 longitude:10]; + XCTAssertNotEqualObjects(userLocation, unarchivedUserLocation); +} +#endif + +#if TARGET_OS_IPHONE +- (void)testUserLocationAnnotationView { + MGLUserLocationAnnotationView *annotationView = [[MGLUserLocationAnnotationView alloc] init]; + annotationView.enabled = NO; + annotationView.selected = YES; + annotationView.draggable = YES; + annotationView.centerOffset = CGVectorMake(10, 10); + annotationView.scalesWithViewingDistance = NO; + + NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocationAnnotationView class]]; + [NSKeyedArchiver archiveRootObject:annotationView toFile:filePath]; + + MGLUserLocationAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + + XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled); + XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected); + XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable); + XCTAssertEqualObjects(NSStringFromCGVector(annotationView.centerOffset), NSStringFromCGVector(unarchivedAnnotationView.centerOffset)); + XCTAssertEqual(annotationView.scalesWithViewingDistance, unarchivedAnnotationView.scalesWithViewingDistance); +} +#endif + +@end diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift new file mode 100644 index 0000000000..d796b4e708 --- /dev/null +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -0,0 +1,220 @@ +import XCTest +import Mapbox +#if os(iOS) + import UIKit +#else + import Cocoa +#endif + +/** + Test cases that ensure the inline examples in the project documentation + compile. + + To add an example: + 1. Add a test case named in the form testMGLClass or testMGLClass$method. + 2. Wrap the code you'd like to appear in the documentation within the + following comment blocks: + ``` + //#-example-code + ... + //#-end-example-code + ``` + 3. Insert an empty Swift code block inside the header file where you'd like the + example code to be inserted. + 4. Run `make darwin-update-examples` to extract example code from the test + method below and insert it into the header. + */ +class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { + var mapView: MGLMapView! + var styleLoadingExpectation: XCTestExpectation! + + override func setUp() { + super.setUp() + let styleURL = Bundle(for: MGLDocumentationExampleTests.self).url(forResource: "one-liner", withExtension: "json") + mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: 256, height: 256), styleURL: styleURL) + mapView.delegate = self + styleLoadingExpectation = expectation(description: "Map view should finish loading style") + waitForExpectations(timeout: 1, handler: nil) + } + + override func tearDown() { + mapView = nil + styleLoadingExpectation = nil + super.tearDown() + } + + func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) { + styleLoadingExpectation.fulfill() + } + + func testMGLShape$shapeWithData_encoding_error_() { + let mainBundle = Bundle(for: MGLDocumentationExampleTests.self) + + //#-example-code + let url = mainBundle.url(forResource: "amsterdam", withExtension: "geojson")! + let data = try! Data(contentsOf: url) + let feature = try! MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature + //#-end-example-code + + XCTAssertNotNil(feature.shapes.first as? MGLPolygonFeature) + } + + func testMGLShapeSource() { + //#-example-code + var coordinates: [CLLocationCoordinate2D] = [ + CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42), + CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04), + ] + let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count)) + let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil) + mapView.style?.addSource(source) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.source(withIdentifier: "lines")) + } + + func testMGLRasterSource() { + //#-example-code + let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .tileSize: 512, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style?.addSource(source) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.source(withIdentifier: "clouds")) + } + + func testMGLVectorSource() { + //#-example-code + let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style?.addSource(source) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois")) + } + + func testMGLCircleStyleLayer() { + let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style?.addSource(population) + + //#-example-code + let layer = MGLCircleStyleLayer(identifier: "circles", source: population) + layer.sourceLayerIdentifier = "population" + layer.circleColor = MGLStyleValue(rawValue: .green) + layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [ + 12: MGLStyleValue(rawValue: 2), + 22: MGLStyleValue(rawValue: 180) + ]) + layer.circleOpacity = MGLStyleValue(rawValue: 0.7) + layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married") + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "circles")) + } + + func testMGLLineStyleLayer() { + let trails = MGLVectorSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style?.addSource(trails) + + //#-example-code + let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails) + layer.sourceLayerIdentifier = "trails" + layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [ + 14: MGLStyleValue(rawValue: 2), + 18: MGLStyleValue(rawValue: 20), + ]) + layer.lineColor = MGLStyleValue(rawValue: .brown) + layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round)) + layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking") + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "trails-path")) + } + + func testMGLFillStyleLayer() { + let parks = MGLVectorSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style?.addSource(parks) + + //#-example-code + let layer = MGLFillStyleLayer(identifier: "parks", source: parks) + layer.sourceLayerIdentifier = "parks" + layer.fillColor = MGLStyleValue(rawValue: .green) + layer.predicate = NSPredicate(format: "type == %@", "national-park") + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "parks")) + } + + func testMGLSymbolStyleLayer() { + let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style?.addSource(pois) + + //#-example-code + let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois) + layer.sourceLayerIdentifier = "pois" + layer.iconImageName = MGLStyleValue(rawValue: "coffee") + layer.iconScale = MGLStyleValue(rawValue: 0.5) + layer.text = MGLStyleValue(rawValue: "{name}") + #if os(macOS) + var vector = CGVector(dx: 10, dy: 0) + layer.textTranslation = MGLStyleValue(rawValue: NSValue(bytes: &vector, objCType: "{CGVector=dd}")) + #else + layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0))) + #endif + layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left)) + layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left)) + layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee") + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "coffeeshops")) + } + + func testMGLRasterStyleLayer() { + let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .tileSize: 512, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style?.addSource(source) + + //#-example-code + let layer = MGLRasterStyleLayer(identifier: "clouds", source: source) + layer.rasterOpacity = MGLStyleValue(rawValue: 0.5) + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "clouds")) + } + + func testMGLVectorStyleLayer$predicate() { + let terrain = MGLVectorSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style?.addSource(terrain) + + //#-example-code + let layer = MGLLineStyleLayer(identifier: "contour", source: terrain) + layer.sourceLayerIdentifier = "contours" + layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0") + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "contour")) + } +} diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index 971f7d0e54..00b57c15f0 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -28,27 +28,35 @@ - (void)testExpressionConversionString { NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"bar"]; - mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue; - XCTAssert(convertedValue.is<std::string>() == true); + mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue; + XCTAssertTrue(convertedValue.is<std::string>()); XCTAssertEqualObjects(@(convertedValue.get<std::string>().c_str()), @"bar"); } +- (void)testExpressionConversionStringWithUnicode +{ + NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"🆔🆗🇦🇶"]; + mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue; + XCTAssertTrue(convertedValue.is<std::string>()); + XCTAssertEqual(convertedValue.get<std::string>(), "🆔🆗🇦🇶"); +} + #pragma mark - Boolean Tests - (void)testExpressionConversionBooleanTrue { NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@YES]; - mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue; - XCTAssert(convertedValue.is<bool>() == true); - XCTAssert(convertedValue.get<bool>() == true); + mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue; + XCTAssertTrue(convertedValue.is<bool>()); + XCTAssertEqual(convertedValue.get<bool>(), true); } - (void)testExpressionConversionBooleanFalse { NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@NO]; - mbgl::Value convertedValue = predicate.rightExpression.mgl_filterValue; - XCTAssert(convertedValue.is<bool>() == true); - XCTAssert(convertedValue.get<bool>() == false); + mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue; + XCTAssertTrue(convertedValue.is<bool>()); + XCTAssertEqual(convertedValue.get<bool>(), false); } #pragma mark - Floating Point Tests @@ -59,12 +67,12 @@ mbgl::Value convertedValue; predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MIN]]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<double>()); XCTAssertEqual(convertedValue.get<double>(), DBL_MIN); predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MAX]]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<double>()); XCTAssertEqual(convertedValue.get<double>(), DBL_MAX); } @@ -72,7 +80,7 @@ - (void)testExpressionConversionFloat { // Because we can't guarantee precision when using float, and because - // we warn the user to this effect in mgl_convertedValueWithValue:, + // we warn the user to this effect in -[NSExpression mgl_constantMBGLValue], // we just check that things are in the ballpark here with integer values // and some lower-precision checks. @@ -80,26 +88,24 @@ mbgl::Value convertedValue; predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-1]]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<double>()); XCTAssertEqual(convertedValue.get<double>(), -1); predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:1]]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<double>()); XCTAssertEqual(convertedValue.get<double>(), 1); predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-23.232342]]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<double>()); - XCTAssertLessThan(-23.24, convertedValue.get<double>()); - XCTAssertGreaterThan(-23.23, convertedValue.get<double>()); + XCTAssertEqualWithAccuracy(convertedValue.get<double>(), -23.232342, 0.000001); predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:23.232342]]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<double>()); - XCTAssertLessThan(23.23, convertedValue.get<double>()); - XCTAssertGreaterThan(23.24, convertedValue.get<double>()); + XCTAssertEqualWithAccuracy(convertedValue.get<double>(), 23.232342, 0.000001); } #pragma mark - Integer Tests @@ -132,7 +138,7 @@ for (NSNumber *min in minValues) { predicate = [self equalityComparisonPredicateWithRightConstantValue:min]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<int64_t>()); XCTAssertEqual(convertedValue.get<int64_t>(), min.longLongValue); } @@ -144,7 +150,7 @@ for (NSNumber *max in maxValues) { predicate = [self equalityComparisonPredicateWithRightConstantValue:max]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<uint64_t>()); XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue); } @@ -179,7 +185,7 @@ for (NSNumber *min in minValues) { predicate = [self equalityComparisonPredicateWithRightConstantValue:min]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<uint64_t>()); XCTAssertEqual(convertedValue.get<uint64_t>(), min.unsignedLongLongValue); } @@ -191,10 +197,19 @@ for (NSNumber *max in maxValues) { predicate = [self equalityComparisonPredicateWithRightConstantValue:max]; - convertedValue = predicate.rightExpression.mgl_filterValue; + convertedValue = predicate.rightExpression.mgl_constantMBGLValue; XCTAssertTrue(convertedValue.is<uint64_t>()); XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue); } } +#pragma mark - Null Tests + +- (void)testExpressionConversionNull +{ + NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNull null]]; + mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue; + XCTAssertTrue(convertedValue.is<mbgl::NullValue>()); +} + @end diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm index efc30d307b..91ec9d429e 100644 --- a/platform/darwin/test/MGLFeatureTests.mm +++ b/platform/darwin/test/MGLFeatureTests.mm @@ -322,6 +322,15 @@ @[@(coord2.longitude), @(coord2.latitude)]]} ]}; XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); + + // When the shape collection is created with an empty array of shapes + shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[]]; + + // it has the correct (empty) geometry + geoJSONFeature = [shapeCollectionFeature geoJSONDictionary]; + expectedGeometry = @{@"type": @"GeometryCollection", + @"geometries": @[]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); } @end diff --git a/platform/darwin/test/MGLFillStyleLayerTests.m b/platform/darwin/test/MGLFillStyleLayerTests.m deleted file mode 100644 index 7d51c15cf4..0000000000 --- a/platform/darwin/test/MGLFillStyleLayerTests.m +++ /dev/null @@ -1,69 +0,0 @@ -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGLFillLayerTests : MGLStyleLayerTests -@end - -@implementation MGLFillLayerTests - -+ (NSString *)layerType { - return @"fill"; -} - -- (void)testFillLayer { - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; - [self.mapView.style addLayer:layer]; - - layer.fillAntialiased = [MGLRuntimeStylingHelper testBool]; - layer.fillColor = [MGLRuntimeStylingHelper testColor]; - layer.fillOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.fillOutlineColor = [MGLRuntimeStylingHelper testColor]; - layer.fillPattern = [MGLRuntimeStylingHelper testString]; - layer.fillTranslate = [MGLRuntimeStylingHelper testOffset]; - layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]; - - MGLFillStyleLayer *gLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGLFillStyleLayer class]]); - XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.fillPattern, [MGLRuntimeStylingHelper testString]); - XCTAssertEqualObjects(gLayer.fillTranslate, [MGLRuntimeStylingHelper testOffset]); - XCTAssert([gLayer.fillTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]); - - layer.fillAntialiased = [MGLRuntimeStylingHelper testBoolFunction]; - layer.fillColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.fillOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.fillOutlineColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.fillPattern = [MGLRuntimeStylingHelper testStringFunction]; - layer.fillTranslate = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.fillTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]; - - XCTAssertEqualObjects(gLayer.fillAntialiased, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.fillColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.fillOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.fillOutlineColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.fillPattern, [MGLRuntimeStylingHelper testStringFunction]); - XCTAssertEqualObjects(gLayer.fillTranslate, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.fillTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLFillTranslateAnchorViewport type:@encode(MGLFillTranslateAnchor)]); -} - -- (void)testPropertyNames { - [self testPropertyName:@"is-fill-antialiased" isBoolean:YES]; - [self testPropertyName:@"fill-color" isBoolean:NO]; - [self testPropertyName:@"fill-opacity" isBoolean:NO]; - [self testPropertyName:@"fill-outline-color" isBoolean:NO]; - [self testPropertyName:@"fill-pattern" isBoolean:NO]; - [self testPropertyName:@"fill-translate" isBoolean:NO]; - [self testPropertyName:@"fill-translate-anchor" isBoolean:NO]; -} - -@end diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm new file mode 100644 index 0000000000..fb50512afd --- /dev/null +++ b/platform/darwin/test/MGLFillStyleLayerTests.mm @@ -0,0 +1,306 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/fill_layer.hpp> + +@interface MGLFillLayerTests : MGLStyleLayerTests +@end + +@implementation MGLFillLayerTests + ++ (NSString *)layerType { + return @"fill"; +} + +- (void)testPredicates { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertNil(layer.sourceLayerIdentifier); + layer.sourceLayerIdentifier = @"layerID"; + XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID"); + layer.sourceLayerIdentifier = nil; + XCTAssertNil(layer.sourceLayerIdentifier); + + XCTAssertNil(layer.predicate); + layer.predicate = [NSPredicate predicateWithValue:NO]; + XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]); + layer.predicate = nil; + XCTAssertNil(layer.predicate); +} + +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::FillLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::FillLayer>(); + + // fill-antialias + { + XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(), + @"fill-antialias should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillAntialiased; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO]; + layer.fillAntialiased = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { false }; + XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue, + @"Setting fillAntialiased to a constant value should update fill-antialias."); + XCTAssertEqualObjects(layer.fillAntialiased, styleValue, + @"fillAntialiased should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillAntialiased = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue, + @"Setting fillAntialiased to a function should update fill-antialias."); + XCTAssertEqualObjects(layer.fillAntialiased, styleValue, + @"fillAntialiased should round-trip functions."); + + layer.fillAntialiased = nil; + XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(), + @"Unsetting fillAntialiased should return fill-antialias to the default value."); + XCTAssertEqualObjects(layer.fillAntialiased, defaultStyleValue, + @"fillAntialiased should return the default value after being unset."); + } + + // fill-color + { + XCTAssertTrue(rawLayer->getFillColor().isUndefined(), + @"fill-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.fillColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getFillColor(), propertyValue, + @"Setting fillColor to a constant value should update fill-color."); + XCTAssertEqualObjects(layer.fillColor, styleValue, + @"fillColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillColor(), propertyValue, + @"Setting fillColor to a function should update fill-color."); + XCTAssertEqualObjects(layer.fillColor, styleValue, + @"fillColor should round-trip functions."); + + layer.fillColor = nil; + XCTAssertTrue(rawLayer->getFillColor().isUndefined(), + @"Unsetting fillColor should return fill-color to the default value."); + XCTAssertEqualObjects(layer.fillColor, defaultStyleValue, + @"fillColor should return the default value after being unset."); + } + + // fill-opacity + { + XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(), + @"fill-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.fillOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue, + @"Setting fillOpacity to a constant value should update fill-opacity."); + XCTAssertEqualObjects(layer.fillOpacity, styleValue, + @"fillOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue, + @"Setting fillOpacity to a function should update fill-opacity."); + XCTAssertEqualObjects(layer.fillOpacity, styleValue, + @"fillOpacity should round-trip functions."); + + layer.fillOpacity = nil; + XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(), + @"Unsetting fillOpacity should return fill-opacity to the default value."); + XCTAssertEqualObjects(layer.fillOpacity, defaultStyleValue, + @"fillOpacity should return the default value after being unset."); + } + + // fill-outline-color + { + XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(), + @"fill-outline-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillOutlineColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.fillOutlineColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue, + @"Setting fillOutlineColor to a constant value should update fill-outline-color."); + XCTAssertEqualObjects(layer.fillOutlineColor, styleValue, + @"fillOutlineColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillOutlineColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue, + @"Setting fillOutlineColor to a function should update fill-outline-color."); + XCTAssertEqualObjects(layer.fillOutlineColor, styleValue, + @"fillOutlineColor should round-trip functions."); + + layer.fillOutlineColor = nil; + XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(), + @"Unsetting fillOutlineColor should return fill-outline-color to the default value."); + XCTAssertEqualObjects(layer.fillOutlineColor, defaultStyleValue, + @"fillOutlineColor should return the default value after being unset."); + } + + // fill-pattern + { + XCTAssertTrue(rawLayer->getFillPattern().isUndefined(), + @"fill-pattern should be unset initially."); + MGLStyleValue<NSString *> *defaultStyleValue = layer.fillPattern; + + MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Pattern"]; + layer.fillPattern = styleValue; + mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Pattern" }; + XCTAssertEqual(rawLayer->getFillPattern(), propertyValue, + @"Setting fillPattern to a constant value should update fill-pattern."); + XCTAssertEqualObjects(layer.fillPattern, styleValue, + @"fillPattern should round-trip constant values."); + + styleValue = [MGLStyleValue<NSString *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillPattern = styleValue; + propertyValue = { mbgl::style::Function<std::string> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillPattern(), propertyValue, + @"Setting fillPattern to a function should update fill-pattern."); + XCTAssertEqualObjects(layer.fillPattern, styleValue, + @"fillPattern should round-trip functions."); + + layer.fillPattern = nil; + XCTAssertTrue(rawLayer->getFillPattern().isUndefined(), + @"Unsetting fillPattern should return fill-pattern to the default value."); + XCTAssertEqualObjects(layer.fillPattern, defaultStyleValue, + @"fillPattern should return the default value after being unset."); + } + + // fill-translate + { + XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(), + @"fill-translate should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslation; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.fillTranslation = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue, + @"Setting fillTranslation to a constant value should update fill-translate."); + XCTAssertEqualObjects(layer.fillTranslation, styleValue, + @"fillTranslation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillTranslation = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue, + @"Setting fillTranslation to a function should update fill-translate."); + XCTAssertEqualObjects(layer.fillTranslation, styleValue, + @"fillTranslation should round-trip functions."); + + layer.fillTranslation = nil; + XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(), + @"Unsetting fillTranslation should return fill-translate to the default value."); + XCTAssertEqualObjects(layer.fillTranslation, defaultStyleValue, + @"fillTranslation should return the default value after being unset."); + } + + // fill-translate-anchor + { + XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(), + @"fill-translate-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslationAnchor; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]]; + layer.fillTranslationAnchor = styleValue; + mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; + XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue, + @"Setting fillTranslationAnchor to a constant value should update fill-translate-anchor."); + XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue, + @"fillTranslationAnchor should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.fillTranslationAnchor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue, + @"Setting fillTranslationAnchor to a function should update fill-translate-anchor."); + XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue, + @"fillTranslationAnchor should round-trip functions."); + + layer.fillTranslationAnchor = nil; + XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(), + @"Unsetting fillTranslationAnchor should return fill-translate-anchor to the default value."); + XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultStyleValue, + @"fillTranslationAnchor should return the default value after being unset."); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"is-fill-antialiased" isBoolean:YES]; + [self testPropertyName:@"fill-color" isBoolean:NO]; + [self testPropertyName:@"fill-opacity" isBoolean:NO]; + [self testPropertyName:@"fill-outline-color" isBoolean:NO]; + [self testPropertyName:@"fill-pattern" isBoolean:NO]; + [self testPropertyName:@"fill-translation" isBoolean:NO]; + [self testPropertyName:@"fill-translation-anchor" isBoolean:NO]; +} + +- (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorMap].MGLFillTranslationAnchorValue, MGLFillTranslationAnchorMap); + XCTAssertEqual([NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport].MGLFillTranslationAnchorValue, MGLFillTranslationAnchorViewport); +} + +@end diff --git a/platform/darwin/test/MGLFilterTests.mm b/platform/darwin/test/MGLFilterTests.mm deleted file mode 100644 index e688d50583..0000000000 --- a/platform/darwin/test/MGLFilterTests.mm +++ /dev/null @@ -1,194 +0,0 @@ -#import "MGLStyleLayerTests.h" - -#import "NSPredicate+MGLAdditions.h" -#import "MGLValueEvaluator.h" - - -@interface MGLFilterTests : MGLStyleLayerTests { - MGLShapeSource *source; - MGLLineStyleLayer *layer; -} -@end - -@implementation MGLFilterTests - -- (void)setUp -{ - [super setUp]; - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - NSData *geoJSONData = [NSData dataWithContentsOfURL:url]; - NSError *error; - MGLShape *shape = [MGLShape shapeWithData:geoJSONData encoding:NSUTF8StringEncoding error:&error]; - XCTAssertNil(error); - XCTAssertNotNil(shape); - source = [[MGLShapeSource alloc] initWithIdentifier:@"test-source" shape:shape options:nil]; - [self.mapView.style addSource:source]; - layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"test-layer" source:source]; -} - -- (void)tearDown -{ - [self.mapView.style removeLayer:layer]; - [self.mapView.style removeSource:source]; -} - -- (NSArray<NSPredicate *> *)predicates -{ - NSPredicate *equalPredicate = [NSPredicate predicateWithFormat:@"type == 'neighbourhood'"]; - NSPredicate *notEqualPredicate = [NSPredicate predicateWithFormat:@"type != 'park'"]; - NSPredicate *greaterThanPredicate = [NSPredicate predicateWithFormat:@"%K > %@", @"stroke-width", @2.1]; - NSPredicate *greaterThanOrEqualToPredicate = [NSPredicate predicateWithFormat:@"%K >= %@", @"stroke-width", @2.1]; - NSPredicate *lessThanOrEqualToPredicate = [NSPredicate predicateWithFormat:@"%K <= %@", @"stroke-width", @2.1]; - NSPredicate *lessThanPredicate = [NSPredicate predicateWithFormat:@"%K < %@", @"stroke-width", @2.1]; - NSPredicate *inPredicate = [NSPredicate predicateWithFormat:@"type IN %@", @[@"park", @"neighbourhood"]]; - NSPredicate *notInPredicate = [NSPredicate predicateWithFormat:@"NOT (type IN %@)", @[@"park", @"neighbourhood"]]; - NSPredicate *inNotInPredicate = [NSPredicate predicateWithFormat:@"type IN %@ AND NOT (type IN %@)", @[@"park"], @[@"neighbourhood", @"test"]]; - NSPredicate *typePredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"$type", @"Feature"]; - NSPredicate *idPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"$id", @"1234123"]; - NSPredicate *specialCharsPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"ty-’pè", @"sŒm-ethįng"]; - NSPredicate *booleanPredicate = [NSPredicate predicateWithFormat:@"cluster != YES"]; - NSPredicate *nilEqualsPredicate = [NSPredicate predicateWithFormat:@"type == %@", nil]; - NSPredicate *nilNotEqualsPredicate = [NSPredicate predicateWithFormat:@"type != %@", nil]; - return @[ - equalPredicate, - notEqualPredicate, - greaterThanPredicate, - greaterThanOrEqualToPredicate, - lessThanOrEqualToPredicate, - lessThanPredicate, - inPredicate, - notInPredicate, - inNotInPredicate, - typePredicate, - idPredicate, - specialCharsPredicate, - booleanPredicate, - nilEqualsPredicate, - nilNotEqualsPredicate - ]; -} - -- (void)testAllPredicates -{ - for (NSPredicate *predicate in self.predicates) { - layer.predicate = predicate; - XCTAssertEqualObjects(layer.predicate, predicate); - } - [self.mapView.style addLayer:layer]; -} - -- (void)testContainsPredicate -{ - // core does not have a "contains" filter but we can achieve the equivalent by creating an `mbgl::style::InFilter` - // and searching the value for the key - NSPredicate *expectedPredicate = [NSPredicate predicateWithFormat:@"park IN %@", @[@"park", @"neighbourhood"]]; - NSPredicate *containsPredicate = [NSPredicate predicateWithFormat:@"%@ CONTAINS %@", @[@"park", @"neighbourhood"], @"park"]; - - layer.predicate = containsPredicate; - XCTAssertEqualObjects(layer.predicate, expectedPredicate); - [self.mapView.style addLayer:layer]; -} - -- (void)testBetweenPredicate -{ - // core does not have a "between" filter but we can achieve the equivalent by creating a set of greater than or equal / less than or equal - // filters for the lower and upper bounds (inclusive) - NSPredicate *expectedPredicate = [NSCompoundPredicate predicateWithFormat:@"%K >= 2 AND %K <= 3", @"stroke-width", @"stroke-width"]; - NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat:@"%K BETWEEN %@", @"stroke-width", @[@2.0, @3.0]]; - - layer.predicate = betweenPredicate; - XCTAssertEqualObjects(layer.predicate, expectedPredicate); - [self.mapView.style addLayer:layer]; -} - -- (void)testTruePredicate -{ - // This comes out of the class cluster as an NSTruePredicate and it is equal to `[NSPredicate predicateWithValue:YES]` - NSPredicate *truePredicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"]; - - layer.predicate = truePredicate; - XCTAssertEqualObjects(layer.predicate.description, truePredicate.description); - [self.mapView.style addLayer:layer]; -} - -- (void)testFalsePredicate -{ - // This comes out of the class cluster as an NSFalsePredicate and it is equal to `[NSPredicate predicateWithValue:NO]` - NSPredicate *falsePredicate = [NSPredicate predicateWithFormat:@"FALSEPREDICATE"]; - - layer.predicate = falsePredicate; - XCTAssertEqualObjects(layer.predicate.description, falsePredicate.description); - [self.mapView.style addLayer:layer]; -} - -- (void)testIntermittentEncoding -{ - NSPredicate *specialCharsPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"ty-’pè", @"sŒm-ethįng"]; - layer.predicate = specialCharsPredicate; - - NSComparisonPredicate *getPredicate = (NSComparisonPredicate *)layer.predicate; - mbgl::style::EqualsFilter filter = layer.predicate.mgl_filter.get<mbgl::style::EqualsFilter>(); - - id objcKey = getPredicate.leftExpression.keyPath; - id cppKey = @(filter.key.c_str()); - id objcValue = mbgl::Value::visit(getPredicate.rightExpression.mgl_filterValue, ValueEvaluator()); - id cppValue = mbgl::Value::visit(filter.value, ValueEvaluator()); - - XCTAssertEqualObjects(objcKey, cppKey); - XCTAssertEqualObjects(objcValue, cppValue); - - [self.mapView.style addLayer:layer]; -} - -- (void)testNestedFilters -{ - NSPredicate *equalPredicate = [NSPredicate predicateWithFormat:@"type == 'neighbourhood'"]; - NSPredicate *notEqualPredicate = [NSPredicate predicateWithFormat:@"type != 'park'"]; - - NSPredicate *allPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[equalPredicate, notEqualPredicate]]; - NSPredicate *anyPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[equalPredicate, notEqualPredicate]]; - - layer.predicate = allPredicate; - XCTAssertEqualObjects(layer.predicate, allPredicate); - layer.predicate = anyPredicate; - XCTAssertEqualObjects(layer.predicate, anyPredicate); - - [self.mapView.style addLayer:layer]; -} - -- (void)testAndPredicates -{ - NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicates]; - layer.predicate = predicate; - XCTAssertEqualObjects(predicate, layer.predicate); - [self.mapView.style addLayer:layer]; -} - -- (void)testOrPredicates -{ - NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicates]; - layer.predicate = predicate; - XCTAssertEqualObjects(predicate, layer.predicate); - [self.mapView.style addLayer:layer]; -} - -- (void)testNotAndPredicates -{ - NSPredicate *predicates = [NSCompoundPredicate andPredicateWithSubpredicates:self.predicates]; - NSCompoundPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:predicates]; - layer.predicate = predicate; - XCTAssertEqualObjects(predicate, layer.predicate); - [self.mapView.style addLayer:layer]; -} - -- (void)testNotOrPredicates -{ - NSPredicate *predicates = [NSCompoundPredicate orPredicateWithSubpredicates:self.predicates]; - NSCompoundPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:predicates]; - layer.predicate = predicate; - XCTAssertEqualObjects(predicate, layer.predicate); - [self.mapView.style addLayer:layer]; -} - -@end diff --git a/platform/darwin/test/MGLLineStyleLayerTests.m b/platform/darwin/test/MGLLineStyleLayerTests.m deleted file mode 100644 index e877c1d57a..0000000000 --- a/platform/darwin/test/MGLLineStyleLayerTests.m +++ /dev/null @@ -1,106 +0,0 @@ -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGLLineLayerTests : MGLStyleLayerTests -@end - -@implementation MGLLineLayerTests - -+ (NSString *)layerType { - return @"line"; -} - -- (void)testLineLayer { - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; - [self.mapView.style addLayer:layer]; - - layer.lineCap = [MGLRuntimeStylingHelper testEnum:MGLLineCapSquare type:@encode(MGLLineCap)]; - layer.lineJoin = [MGLRuntimeStylingHelper testEnum:MGLLineJoinMiter type:@encode(MGLLineJoin)]; - layer.lineMiterLimit = [MGLRuntimeStylingHelper testNumber]; - layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumber]; - layer.lineBlur = [MGLRuntimeStylingHelper testNumber]; - layer.lineColor = [MGLRuntimeStylingHelper testColor]; - layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArray]; - layer.lineGapWidth = [MGLRuntimeStylingHelper testNumber]; - layer.lineOffset = [MGLRuntimeStylingHelper testNumber]; - layer.lineOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.linePattern = [MGLRuntimeStylingHelper testString]; - layer.lineTranslate = [MGLRuntimeStylingHelper testOffset]; - layer.lineTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]; - layer.lineWidth = [MGLRuntimeStylingHelper testNumber]; - - MGLLineStyleLayer *gLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGLLineStyleLayer class]]); - XCTAssert([gLayer.lineCap isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.lineCap, [MGLRuntimeStylingHelper testEnum:MGLLineCapSquare type:@encode(MGLLineCap)]); - XCTAssert([gLayer.lineJoin isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.lineJoin, [MGLRuntimeStylingHelper testEnum:MGLLineJoinMiter type:@encode(MGLLineJoin)]); - XCTAssertEqualObjects(gLayer.lineMiterLimit, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArray]); - XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.linePattern, [MGLRuntimeStylingHelper testString]); - XCTAssertEqualObjects(gLayer.lineTranslate, [MGLRuntimeStylingHelper testOffset]); - XCTAssert([gLayer.lineTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.lineTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]); - XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumber]); - - layer.lineCap = [MGLRuntimeStylingHelper testEnumFunction:MGLLineCapSquare type:@encode(MGLLineCap)]; - layer.lineJoin = [MGLRuntimeStylingHelper testEnumFunction:MGLLineJoinMiter type:@encode(MGLLineJoin)]; - layer.lineMiterLimit = [MGLRuntimeStylingHelper testNumberFunction]; - layer.lineRoundLimit = [MGLRuntimeStylingHelper testNumberFunction]; - layer.lineBlur = [MGLRuntimeStylingHelper testNumberFunction]; - layer.lineColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.lineDashPattern = [MGLRuntimeStylingHelper testDashArrayFunction]; - layer.lineGapWidth = [MGLRuntimeStylingHelper testNumberFunction]; - layer.lineOffset = [MGLRuntimeStylingHelper testNumberFunction]; - layer.lineOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.linePattern = [MGLRuntimeStylingHelper testStringFunction]; - layer.lineTranslate = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.lineTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]; - layer.lineWidth = [MGLRuntimeStylingHelper testNumberFunction]; - - XCTAssertEqualObjects(gLayer.lineCap, [MGLRuntimeStylingHelper testEnumFunction:MGLLineCapSquare type:@encode(MGLLineCap)]); - XCTAssertEqualObjects(gLayer.lineJoin, [MGLRuntimeStylingHelper testEnumFunction:MGLLineJoinMiter type:@encode(MGLLineJoin)]); - XCTAssertEqualObjects(gLayer.lineMiterLimit, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.lineRoundLimit, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.lineBlur, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.lineColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.lineDashPattern, [MGLRuntimeStylingHelper testDashArrayFunction]); - XCTAssertEqualObjects(gLayer.lineGapWidth, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.lineOffset, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.lineOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.linePattern, [MGLRuntimeStylingHelper testStringFunction]); - XCTAssertEqualObjects(gLayer.lineTranslate, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.lineTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLLineTranslateAnchorViewport type:@encode(MGLLineTranslateAnchor)]); - XCTAssertEqualObjects(gLayer.lineWidth, [MGLRuntimeStylingHelper testNumberFunction]); -} - -- (void)testPropertyNames { - [self testPropertyName:@"line-cap" isBoolean:NO]; - [self testPropertyName:@"line-join" isBoolean:NO]; - [self testPropertyName:@"line-miter-limit" isBoolean:NO]; - [self testPropertyName:@"line-round-limit" isBoolean:NO]; - [self testPropertyName:@"line-blur" isBoolean:NO]; - [self testPropertyName:@"line-color" isBoolean:NO]; - [self testPropertyName:@"line-dash-pattern" isBoolean:NO]; - [self testPropertyName:@"line-gap-width" isBoolean:NO]; - [self testPropertyName:@"line-offset" isBoolean:NO]; - [self testPropertyName:@"line-opacity" isBoolean:NO]; - [self testPropertyName:@"line-pattern" isBoolean:NO]; - [self testPropertyName:@"line-translate" isBoolean:NO]; - [self testPropertyName:@"line-translate-anchor" isBoolean:NO]; - [self testPropertyName:@"line-width" isBoolean:NO]; -} - -@end diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm new file mode 100644 index 0000000000..24a9d7afea --- /dev/null +++ b/platform/darwin/test/MGLLineStyleLayerTests.mm @@ -0,0 +1,557 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/line_layer.hpp> + +@interface MGLLineLayerTests : MGLStyleLayerTests +@end + +@implementation MGLLineLayerTests + ++ (NSString *)layerType { + return @"line"; +} + +- (void)testPredicates { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertNil(layer.sourceLayerIdentifier); + layer.sourceLayerIdentifier = @"layerID"; + XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID"); + layer.sourceLayerIdentifier = nil; + XCTAssertNil(layer.sourceLayerIdentifier); + + XCTAssertNil(layer.predicate); + layer.predicate = [NSPredicate predicateWithValue:NO]; + XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]); + layer.predicate = nil; + XCTAssertNil(layer.predicate); +} + +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::LineLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::LineLayer>(); + + // line-cap + { + XCTAssertTrue(rawLayer->getLineCap().isUndefined(), + @"line-cap should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineCap; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]]; + layer.lineCap = styleValue; + mbgl::style::PropertyValue<mbgl::style::LineCapType> propertyValue = { mbgl::style::LineCapType::Square }; + XCTAssertEqual(rawLayer->getLineCap(), propertyValue, + @"Setting lineCap to a constant value should update line-cap."); + XCTAssertEqualObjects(layer.lineCap, styleValue, + @"lineCap should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineCap = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::LineCapType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineCap(), propertyValue, + @"Setting lineCap to a function should update line-cap."); + XCTAssertEqualObjects(layer.lineCap, styleValue, + @"lineCap should round-trip functions."); + + layer.lineCap = nil; + XCTAssertTrue(rawLayer->getLineCap().isUndefined(), + @"Unsetting lineCap should return line-cap to the default value."); + XCTAssertEqualObjects(layer.lineCap, defaultStyleValue, + @"lineCap should return the default value after being unset."); + } + + // line-join + { + XCTAssertTrue(rawLayer->getLineJoin().isUndefined(), + @"line-join should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineJoin; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]]; + layer.lineJoin = styleValue; + mbgl::style::PropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter }; + XCTAssertEqual(rawLayer->getLineJoin(), propertyValue, + @"Setting lineJoin to a constant value should update line-join."); + XCTAssertEqualObjects(layer.lineJoin, styleValue, + @"lineJoin should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineJoin = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::LineJoinType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineJoin(), propertyValue, + @"Setting lineJoin to a function should update line-join."); + XCTAssertEqualObjects(layer.lineJoin, styleValue, + @"lineJoin should round-trip functions."); + + layer.lineJoin = nil; + XCTAssertTrue(rawLayer->getLineJoin().isUndefined(), + @"Unsetting lineJoin should return line-join to the default value."); + XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue, + @"lineJoin should return the default value after being unset."); + } + + // line-miter-limit + { + XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(), + @"line-miter-limit should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineMiterLimit; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineMiterLimit = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue, + @"Setting lineMiterLimit to a constant value should update line-miter-limit."); + XCTAssertEqualObjects(layer.lineMiterLimit, styleValue, + @"lineMiterLimit should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineMiterLimit = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue, + @"Setting lineMiterLimit to a function should update line-miter-limit."); + XCTAssertEqualObjects(layer.lineMiterLimit, styleValue, + @"lineMiterLimit should round-trip functions."); + + layer.lineMiterLimit = nil; + XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(), + @"Unsetting lineMiterLimit should return line-miter-limit to the default value."); + XCTAssertEqualObjects(layer.lineMiterLimit, defaultStyleValue, + @"lineMiterLimit should return the default value after being unset."); + } + + // line-round-limit + { + XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(), + @"line-round-limit should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineRoundLimit; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineRoundLimit = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue, + @"Setting lineRoundLimit to a constant value should update line-round-limit."); + XCTAssertEqualObjects(layer.lineRoundLimit, styleValue, + @"lineRoundLimit should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineRoundLimit = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue, + @"Setting lineRoundLimit to a function should update line-round-limit."); + XCTAssertEqualObjects(layer.lineRoundLimit, styleValue, + @"lineRoundLimit should round-trip functions."); + + layer.lineRoundLimit = nil; + XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(), + @"Unsetting lineRoundLimit should return line-round-limit to the default value."); + XCTAssertEqualObjects(layer.lineRoundLimit, defaultStyleValue, + @"lineRoundLimit should return the default value after being unset."); + } + + // line-blur + { + XCTAssertTrue(rawLayer->getLineBlur().isUndefined(), + @"line-blur should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineBlur; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineBlur = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineBlur(), propertyValue, + @"Setting lineBlur to a constant value should update line-blur."); + XCTAssertEqualObjects(layer.lineBlur, styleValue, + @"lineBlur should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineBlur = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineBlur(), propertyValue, + @"Setting lineBlur to a function should update line-blur."); + XCTAssertEqualObjects(layer.lineBlur, styleValue, + @"lineBlur should round-trip functions."); + + layer.lineBlur = nil; + XCTAssertTrue(rawLayer->getLineBlur().isUndefined(), + @"Unsetting lineBlur should return line-blur to the default value."); + XCTAssertEqualObjects(layer.lineBlur, defaultStyleValue, + @"lineBlur should return the default value after being unset."); + } + + // line-color + { + XCTAssertTrue(rawLayer->getLineColor().isUndefined(), + @"line-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.lineColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.lineColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getLineColor(), propertyValue, + @"Setting lineColor to a constant value should update line-color."); + XCTAssertEqualObjects(layer.lineColor, styleValue, + @"lineColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineColor(), propertyValue, + @"Setting lineColor to a function should update line-color."); + XCTAssertEqualObjects(layer.lineColor, styleValue, + @"lineColor should round-trip functions."); + + layer.lineColor = nil; + XCTAssertTrue(rawLayer->getLineColor().isUndefined(), + @"Unsetting lineColor should return line-color to the default value."); + XCTAssertEqualObjects(layer.lineColor, defaultStyleValue, + @"lineColor should return the default value after being unset."); + } + + // line-dasharray + { + XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(), + @"line-dasharray should be unset initially."); + MGLStyleValue<NSArray<NSNumber *> *> *defaultStyleValue = layer.lineDashPattern; + + MGLStyleValue<NSArray<NSNumber *> *> *styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]]; + layer.lineDashPattern = styleValue; + mbgl::style::PropertyValue<std::vector<float>> propertyValue = { {1, 2} }; + XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue, + @"Setting lineDashPattern to a constant value should update line-dasharray."); + XCTAssertEqualObjects(layer.lineDashPattern, styleValue, + @"lineDashPattern should round-trip constant values."); + + styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineDashPattern = styleValue; + propertyValue = { mbgl::style::Function<std::vector<float>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue, + @"Setting lineDashPattern to a function should update line-dasharray."); + XCTAssertEqualObjects(layer.lineDashPattern, styleValue, + @"lineDashPattern should round-trip functions."); + + layer.lineDashPattern = nil; + XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(), + @"Unsetting lineDashPattern should return line-dasharray to the default value."); + XCTAssertEqualObjects(layer.lineDashPattern, defaultStyleValue, + @"lineDashPattern should return the default value after being unset."); + } + + // line-gap-width + { + XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(), + @"line-gap-width should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineGapWidth; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineGapWidth = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue, + @"Setting lineGapWidth to a constant value should update line-gap-width."); + XCTAssertEqualObjects(layer.lineGapWidth, styleValue, + @"lineGapWidth should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineGapWidth = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue, + @"Setting lineGapWidth to a function should update line-gap-width."); + XCTAssertEqualObjects(layer.lineGapWidth, styleValue, + @"lineGapWidth should round-trip functions."); + + layer.lineGapWidth = nil; + XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(), + @"Unsetting lineGapWidth should return line-gap-width to the default value."); + XCTAssertEqualObjects(layer.lineGapWidth, defaultStyleValue, + @"lineGapWidth should return the default value after being unset."); + } + + // line-offset + { + XCTAssertTrue(rawLayer->getLineOffset().isUndefined(), + @"line-offset should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOffset; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineOffset = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineOffset(), propertyValue, + @"Setting lineOffset to a constant value should update line-offset."); + XCTAssertEqualObjects(layer.lineOffset, styleValue, + @"lineOffset should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineOffset = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineOffset(), propertyValue, + @"Setting lineOffset to a function should update line-offset."); + XCTAssertEqualObjects(layer.lineOffset, styleValue, + @"lineOffset should round-trip functions."); + + layer.lineOffset = nil; + XCTAssertTrue(rawLayer->getLineOffset().isUndefined(), + @"Unsetting lineOffset should return line-offset to the default value."); + XCTAssertEqualObjects(layer.lineOffset, defaultStyleValue, + @"lineOffset should return the default value after being unset."); + } + + // line-opacity + { + XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(), + @"line-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue, + @"Setting lineOpacity to a constant value should update line-opacity."); + XCTAssertEqualObjects(layer.lineOpacity, styleValue, + @"lineOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue, + @"Setting lineOpacity to a function should update line-opacity."); + XCTAssertEqualObjects(layer.lineOpacity, styleValue, + @"lineOpacity should round-trip functions."); + + layer.lineOpacity = nil; + XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(), + @"Unsetting lineOpacity should return line-opacity to the default value."); + XCTAssertEqualObjects(layer.lineOpacity, defaultStyleValue, + @"lineOpacity should return the default value after being unset."); + } + + // line-pattern + { + XCTAssertTrue(rawLayer->getLinePattern().isUndefined(), + @"line-pattern should be unset initially."); + MGLStyleValue<NSString *> *defaultStyleValue = layer.linePattern; + + MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Line Pattern"]; + layer.linePattern = styleValue; + mbgl::style::PropertyValue<std::string> propertyValue = { "Line Pattern" }; + XCTAssertEqual(rawLayer->getLinePattern(), propertyValue, + @"Setting linePattern to a constant value should update line-pattern."); + XCTAssertEqualObjects(layer.linePattern, styleValue, + @"linePattern should round-trip constant values."); + + styleValue = [MGLStyleValue<NSString *> valueWithStops:@{ + @18: styleValue, + }]; + layer.linePattern = styleValue; + propertyValue = { mbgl::style::Function<std::string> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLinePattern(), propertyValue, + @"Setting linePattern to a function should update line-pattern."); + XCTAssertEqualObjects(layer.linePattern, styleValue, + @"linePattern should round-trip functions."); + + layer.linePattern = nil; + XCTAssertTrue(rawLayer->getLinePattern().isUndefined(), + @"Unsetting linePattern should return line-pattern to the default value."); + XCTAssertEqualObjects(layer.linePattern, defaultStyleValue, + @"linePattern should return the default value after being unset."); + } + + // line-translate + { + XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(), + @"line-translate should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslation; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.lineTranslation = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue, + @"Setting lineTranslation to a constant value should update line-translate."); + XCTAssertEqualObjects(layer.lineTranslation, styleValue, + @"lineTranslation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineTranslation = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue, + @"Setting lineTranslation to a function should update line-translate."); + XCTAssertEqualObjects(layer.lineTranslation, styleValue, + @"lineTranslation should round-trip functions."); + + layer.lineTranslation = nil; + XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(), + @"Unsetting lineTranslation should return line-translate to the default value."); + XCTAssertEqualObjects(layer.lineTranslation, defaultStyleValue, + @"lineTranslation should return the default value after being unset."); + } + + // line-translate-anchor + { + XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(), + @"line-translate-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslationAnchor; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]]; + layer.lineTranslationAnchor = styleValue; + mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; + XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue, + @"Setting lineTranslationAnchor to a constant value should update line-translate-anchor."); + XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue, + @"lineTranslationAnchor should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineTranslationAnchor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue, + @"Setting lineTranslationAnchor to a function should update line-translate-anchor."); + XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue, + @"lineTranslationAnchor should round-trip functions."); + + layer.lineTranslationAnchor = nil; + XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(), + @"Unsetting lineTranslationAnchor should return line-translate-anchor to the default value."); + XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultStyleValue, + @"lineTranslationAnchor should return the default value after being unset."); + } + + // line-width + { + XCTAssertTrue(rawLayer->getLineWidth().isUndefined(), + @"line-width should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineWidth; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.lineWidth = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getLineWidth(), propertyValue, + @"Setting lineWidth to a constant value should update line-width."); + XCTAssertEqualObjects(layer.lineWidth, styleValue, + @"lineWidth should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.lineWidth = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getLineWidth(), propertyValue, + @"Setting lineWidth to a function should update line-width."); + XCTAssertEqualObjects(layer.lineWidth, styleValue, + @"lineWidth should round-trip functions."); + + layer.lineWidth = nil; + XCTAssertTrue(rawLayer->getLineWidth().isUndefined(), + @"Unsetting lineWidth should return line-width to the default value."); + XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue, + @"lineWidth should return the default value after being unset."); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"line-cap" isBoolean:NO]; + [self testPropertyName:@"line-join" isBoolean:NO]; + [self testPropertyName:@"line-miter-limit" isBoolean:NO]; + [self testPropertyName:@"line-round-limit" isBoolean:NO]; + [self testPropertyName:@"line-blur" isBoolean:NO]; + [self testPropertyName:@"line-color" isBoolean:NO]; + [self testPropertyName:@"line-dash-pattern" isBoolean:NO]; + [self testPropertyName:@"line-gap-width" isBoolean:NO]; + [self testPropertyName:@"line-offset" isBoolean:NO]; + [self testPropertyName:@"line-opacity" isBoolean:NO]; + [self testPropertyName:@"line-pattern" isBoolean:NO]; + [self testPropertyName:@"line-translation" isBoolean:NO]; + [self testPropertyName:@"line-translation-anchor" isBoolean:NO]; + [self testPropertyName:@"line-width" isBoolean:NO]; +} + +- (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapButt].MGLLineCapValue, MGLLineCapButt); + XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapRound].MGLLineCapValue, MGLLineCapRound); + XCTAssertEqual([NSValue valueWithMGLLineCap:MGLLineCapSquare].MGLLineCapValue, MGLLineCapSquare); + XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinBevel].MGLLineJoinValue, MGLLineJoinBevel); + XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinRound].MGLLineJoinValue, MGLLineJoinRound); + XCTAssertEqual([NSValue valueWithMGLLineJoin:MGLLineJoinMiter].MGLLineJoinValue, MGLLineJoinMiter); + XCTAssertEqual([NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorMap].MGLLineTranslationAnchorValue, MGLLineTranslationAnchorMap); + XCTAssertEqual([NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport].MGLLineTranslationAnchorValue, MGLLineTranslationAnchorViewport); +} + +@end diff --git a/platform/darwin/test/MGLNSStringAdditionsTests.m b/platform/darwin/test/MGLNSStringAdditionsTests.m new file mode 100644 index 0000000000..0c8a9f8143 --- /dev/null +++ b/platform/darwin/test/MGLNSStringAdditionsTests.m @@ -0,0 +1,42 @@ +#import <XCTest/XCTest.h> + +#import "NSString+MGLAdditions.h" + +@interface MGLNSStringAdditionsTests : XCTestCase + +@end + +@implementation MGLNSStringAdditionsTests + +- (void)testTitleCasedString { + NSLocale *locale = [NSLocale currentLocale]; + + XCTAssertEqualObjects([@"© OpenStreetMap" mgl_titleCasedStringWithLocale:locale], @"© OpenStreetMap"); + XCTAssertEqualObjects([@"© OSM" mgl_titleCasedStringWithLocale:locale], @"© OSM"); + + XCTAssertEqualObjects([@"Improve this map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map"); + XCTAssertEqualObjects([@"Improve This Map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map"); + + XCTAssertEqualObjects([@"Improve the map" mgl_titleCasedStringWithLocale:locale], @"Improve the Map"); + XCTAssertEqualObjects([@"Improve The Map" mgl_titleCasedStringWithLocale:locale], @"Improve The Map"); + + XCTAssertEqualObjects([@"Improve a map" mgl_titleCasedStringWithLocale:locale], @"Improve a Map"); + XCTAssertEqualObjects([@"Improve A Map" mgl_titleCasedStringWithLocale:locale], @"Improve A Map"); + + XCTAssertEqualObjects([@"Improve for the map" mgl_titleCasedStringWithLocale:locale], @"Improve for the Map"); + XCTAssertEqualObjects([@"Improve For The Map" mgl_titleCasedStringWithLocale:locale], @"Improve For The Map"); + + XCTAssertEqualObjects([@"Improve and map" mgl_titleCasedStringWithLocale:locale], @"Improve and Map"); + XCTAssertEqualObjects([@"Improve And Map" mgl_titleCasedStringWithLocale:locale], @"Improve And Map"); + + XCTAssertEqualObjects([@"Improve while mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping"); + XCTAssertEqualObjects([@"Improve While Mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping"); + + XCTAssertEqualObjects([@"Improve with the map" mgl_titleCasedStringWithLocale:locale], @"Improve With the Map"); + XCTAssertEqualObjects([@"Improve With The Map" mgl_titleCasedStringWithLocale:locale], @"Improve With The Map"); + + XCTAssertEqualObjects([@"Improve this iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone"); + XCTAssertEqualObjects([@"Improve This iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone"); +} + +@end diff --git a/platform/darwin/test/MGLPredicateTests.mm b/platform/darwin/test/MGLPredicateTests.mm new file mode 100644 index 0000000000..fbd144d28a --- /dev/null +++ b/platform/darwin/test/MGLPredicateTests.mm @@ -0,0 +1,419 @@ +#import <XCTest/XCTest.h> +#import <Mapbox/Mapbox.h> + +#import "NSPredicate+MGLAdditions.h" +#import "MGLValueEvaluator.h" + +namespace mbgl { + namespace style { + bool operator!=(const Filter &a, const Filter &b) { + return !(a == b); + } + } +} + +#define MGLAssertEqualFilters(actual, expected, ...) \ + XCTAssertTrue(actual.is<__typeof__(expected)>()); \ + if (actual.is<__typeof__(expected)>()) { \ + XCTAssertEqual(actual.get<__typeof__(expected)>(), expected, __VA_ARGS__); \ + } + +@interface MGLPredicateTests : XCTestCase +@end + +@implementation MGLPredicateTests + +- (void)testFilterization { + { + auto actual = [NSPredicate predicateWithValue:YES].mgl_filter; + mbgl::style::AllFilter expected; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithValue:NO].mgl_filter; + mbgl::style::AnyFilter expected; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a = 'b'"].mgl_filter; + mbgl::style::EqualsFilter expected = { .key = "a", .value = std::string("b") }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a = nil"].mgl_filter; + mbgl::style::NotHasFilter expected = { .key = "a" }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a != 'b'"].mgl_filter; + mbgl::style::NotEqualsFilter expected = { .key = "a", .value = std::string("b") }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a != nil"].mgl_filter; + mbgl::style::HasFilter expected = { .key = "a" }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a < 'b'"].mgl_filter; + mbgl::style::LessThanFilter expected = { .key = "a", .value = std::string("b") }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a <= 'b'"].mgl_filter; + mbgl::style::LessThanEqualsFilter expected = { .key = "a", .value = std::string("b") }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a > 'b'"].mgl_filter; + mbgl::style::GreaterThanFilter expected = { .key = "a", .value = std::string("b") }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a >= 'b'"].mgl_filter; + mbgl::style::GreaterThanEqualsFilter expected = { .key = "a", .value = std::string("b") }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"].mgl_filter; + mbgl::style::AllFilter expected = { + .filters = { + mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") }, + }, + }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@"b", @"z"]].mgl_filter; + mbgl::style::AllFilter expected = { + .filters = { + mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") }, + }, + }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].mgl_filter; + mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a IN %@", @[@"b", @"c"]].mgl_filter; + mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"'Mapbox' IN a"].mgl_filter, NSException, NSInvalidArgumentException); + + { + auto actual = [NSPredicate predicateWithFormat:@"{'b', 'c'} CONTAINS a"].mgl_filter; + mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@"b", @"c"]].mgl_filter; + mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a CONTAINS 'Mapbox'"].mgl_filter, NSException, NSInvalidArgumentException); + + { + auto actual = [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"].mgl_filter; + mbgl::style::AllFilter expected = { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"].mgl_filter; + mbgl::style::AnyFilter expected = { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' AND c == 'd')"].mgl_filter; + mbgl::style::NoneFilter expected = { + .filters = { + mbgl::style::AllFilter { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }, + }, + }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"].mgl_filter; + mbgl::style::NoneFilter expected = { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT a == nil"].mgl_filter; + mbgl::style::HasFilter expected = { .key = "a" }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT a != nil"].mgl_filter; + mbgl::style::NotHasFilter expected = { .key = "a" }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].mgl_filter; + mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT a IN %@", @[@"b", @"c"]].mgl_filter; + mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT {'b', 'c'} CONTAINS a"].mgl_filter; + mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"NOT %@ CONTAINS a", @[@"b", @"c"]].mgl_filter; + mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; + MGLAssertEqualFilters(actual, expected); + } + + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BEGINSWITH 'L'"].mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a ENDSWITH 'itude'"].mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a LIKE 'glob?trotter'"].mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a MATCHES 'i\\w{18}n'"].mgl_filter, NSException, NSInvalidArgumentException); + NSPredicate *selectorPredicate = [NSPredicate predicateWithFormat:@"(SELF isKindOfClass: %@)", [MGLPolyline class]]; + XCTAssertThrowsSpecificNamed(selectorPredicate.mgl_filter, NSException, NSInvalidArgumentException); + + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings) { + XCTAssertTrue(NO, @"Predicate block should not be evaluated."); + return NO; + }].mgl_filter, NSException, NSInvalidArgumentException); +} + +- (void)testPredication { + XCTAssertNil([NSPredicate mgl_predicateWithFilter:mbgl::style::NullFilter()]); + + { + mbgl::style::EqualsFilter filter = { .key = "a", .value = std::string("b") }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = 'b'"]); + } + + { + mbgl::style::NotHasFilter filter = { .key = "a" }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = nil"]); + } + + { + mbgl::style::NotEqualsFilter filter = { .key = "a", .value = std::string("b") }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != 'b'"]); + } + + { + mbgl::style::HasFilter filter = { .key = "a" }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != nil"]); + } + + { + mbgl::style::LessThanFilter filter = { .key = "a", .value = std::string("b") }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a < 'b'"]); + } + + { + mbgl::style::LessThanEqualsFilter filter = { .key = "a", .value = std::string("b") }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a <= 'b'"]); + } + + { + mbgl::style::GreaterThanFilter filter = { .key = "a", .value = std::string("b") }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a > 'b'"]); + } + + { + mbgl::style::GreaterThanEqualsFilter filter = { .key = "a", .value = std::string("b") }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a >= 'b'"]); + } + + { + mbgl::style::AllFilter filter = { + .filters = { + mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") }, + }, + }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]); + } + + { + mbgl::style::AllFilter filter = { + .filters = { + mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") }, + mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") }, + }, + }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]); + } + + { + mbgl::style::InFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].predicateFormat); + } + + { + mbgl::style::NotInFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].predicateFormat); + } + + { + mbgl::style::AllFilter filter; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]); + } + + { + mbgl::style::AllFilter filter = { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"]); + } + + { + mbgl::style::AnyFilter filter; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:NO]); + } + + { + mbgl::style::AnyFilter filter = { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"]); + } + + { + mbgl::style::NoneFilter filter; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]); + } + + { + mbgl::style::NoneFilter filter = { + .filters = { + mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") }, + mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") }, + }, + }; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"]); + } +} + +- (void)testSymmetry { + [self testSymmetryWithFormat:@"a = 1" reverseFormat:@"1 = a" mustRoundTrip:YES]; + [self testSymmetryWithFormat:@"a != 1" reverseFormat:@"1 != a" mustRoundTrip:YES]; + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = b"].mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"1 = 1"].mgl_filter, NSException, NSInvalidArgumentException); + + // In the predicate format language, $ is a special character denoting a + // variable. Use %K to escape the special feature attribute $id. + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"$id == 670861802"].mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = $id"].mgl_filter, NSException, NSInvalidArgumentException); + + [self testSymmetryWithFormat:@"a = nil" reverseFormat:@"nil = a" mustRoundTrip:YES]; + [self testSymmetryWithFormat:@"a != nil" reverseFormat:@"nil != a" mustRoundTrip:YES]; + + [self testSymmetryWithFormat:@"a < 1" reverseFormat:@"1 > a" mustRoundTrip:YES]; + [self testSymmetryWithFormat:@"a <= 1" reverseFormat:@"1 >= a" mustRoundTrip:YES]; + [self testSymmetryWithFormat:@"a > 1" reverseFormat:@"1 < a" mustRoundTrip:YES]; + [self testSymmetryWithFormat:@"a >= 1" reverseFormat:@"1 <= a" mustRoundTrip:YES]; + + [self testSymmetryWithFormat:@"a BETWEEN {1, 2}" reverseFormat:@"1 <= a && 2 >= a" mustRoundTrip:YES]; + [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@1, @2]] + reversePredicate:[NSPredicate predicateWithFormat:@"1 <= a && 2 >= a"] + mustRoundTrip:YES]; + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"{1, 2} BETWEEN a"].mgl_filter, NSException, NSInvalidArgumentException); + NSPredicate *betweenSetPredicate = [NSPredicate predicateWithFormat:@"a BETWEEN %@", [NSSet setWithObjects:@1, @2, nil]]; + XCTAssertThrowsSpecificNamed(betweenSetPredicate.mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1}"].mgl_filter, NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1, 2, 3}"].mgl_filter, NSException, NSInvalidArgumentException); + + [self testSymmetryWithFormat:@"a IN {1, 2}" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO]; + [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a IN %@", @[@1, @2]] + reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]] + mustRoundTrip:YES]; + + // The reverse formats here are a bit backwards because we canonicalize + // a reverse CONTAINS to a forward IN. + [self testSymmetryWithFormat:@"{1, 2} CONTAINS a" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO]; + [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]] + reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]] + mustRoundTrip:NO]; +} + +- (void)testSymmetryWithFormat:(NSString *)forwardFormat reverseFormat:(NSString *)reverseFormat mustRoundTrip:(BOOL)mustRoundTrip { + NSPredicate *forwardPredicate = [NSPredicate predicateWithFormat:forwardFormat]; + NSPredicate *reversePredicate = reverseFormat ? [NSPredicate predicateWithFormat:reverseFormat] : nil; + [self testSymmetryWithPredicate:forwardPredicate reversePredicate:reversePredicate mustRoundTrip:mustRoundTrip]; +} + +- (void)testSymmetryWithPredicate:(NSPredicate *)forwardPredicate reversePredicate:(NSPredicate *)reversePredicate mustRoundTrip:(BOOL)mustRoundTrip { + auto forwardFilter = forwardPredicate.mgl_filter; + NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter]; + if (mustRoundTrip) { + // A collection of ints may turn into an aggregate of longs, for + // example, so compare formats instead of the predicates themselves. + XCTAssertEqualObjects(forwardPredicate.predicateFormat, forwardPredicateAfter.predicateFormat); + } + + if (reversePredicate) { + auto reverseFilter = reversePredicate.mgl_filter; + NSPredicate *reversePredicateAfter = [NSPredicate mgl_predicateWithFilter:reverseFilter]; + XCTAssertNotEqualObjects(reversePredicate, reversePredicateAfter); + + XCTAssertEqualObjects(forwardPredicateAfter, reversePredicateAfter); + } +} + +@end diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.m b/platform/darwin/test/MGLRasterStyleLayerTests.m deleted file mode 100644 index f8de191da0..0000000000 --- a/platform/darwin/test/MGLRasterStyleLayerTests.m +++ /dev/null @@ -1,68 +0,0 @@ -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGLRasterLayerTests : MGLStyleLayerTests -@end - -@implementation MGLRasterLayerTests - -+ (NSString *)layerType { - return @"raster"; -} - -- (void)testRasterLayer { - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGLRasterStyleLayer *layer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; - [self.mapView.style addLayer:layer]; - - layer.maximumRasterBrightness = [MGLRuntimeStylingHelper testNumber]; - layer.minimumRasterBrightness = [MGLRuntimeStylingHelper testNumber]; - layer.rasterContrast = [MGLRuntimeStylingHelper testNumber]; - layer.rasterFadeDuration = [MGLRuntimeStylingHelper testNumber]; - layer.rasterHueRotation = [MGLRuntimeStylingHelper testNumber]; - layer.rasterOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.rasterSaturation = [MGLRuntimeStylingHelper testNumber]; - - MGLRasterStyleLayer *gLayer = (MGLRasterStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGLRasterStyleLayer class]]); - XCTAssertEqualObjects(gLayer.maximumRasterBrightness, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.minimumRasterBrightness, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.rasterContrast, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.rasterFadeDuration, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.rasterHueRotation, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.rasterOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.rasterSaturation, [MGLRuntimeStylingHelper testNumber]); - - layer.maximumRasterBrightness = [MGLRuntimeStylingHelper testNumberFunction]; - layer.minimumRasterBrightness = [MGLRuntimeStylingHelper testNumberFunction]; - layer.rasterContrast = [MGLRuntimeStylingHelper testNumberFunction]; - layer.rasterFadeDuration = [MGLRuntimeStylingHelper testNumberFunction]; - layer.rasterHueRotation = [MGLRuntimeStylingHelper testNumberFunction]; - layer.rasterOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.rasterSaturation = [MGLRuntimeStylingHelper testNumberFunction]; - - XCTAssertEqualObjects(gLayer.maximumRasterBrightness, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.minimumRasterBrightness, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.rasterContrast, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.rasterFadeDuration, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.rasterHueRotation, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.rasterOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.rasterSaturation, [MGLRuntimeStylingHelper testNumberFunction]); -} - -- (void)testPropertyNames { - [self testPropertyName:@"maximum-raster-brightness" isBoolean:NO]; - [self testPropertyName:@"minimum-raster-brightness" isBoolean:NO]; - [self testPropertyName:@"raster-contrast" isBoolean:NO]; - [self testPropertyName:@"raster-fade-duration" isBoolean:NO]; - [self testPropertyName:@"raster-hue-rotation" isBoolean:NO]; - [self testPropertyName:@"raster-opacity" isBoolean:NO]; - [self testPropertyName:@"raster-saturation" isBoolean:NO]; -} - -@end diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm new file mode 100644 index 0000000000..28a201961c --- /dev/null +++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm @@ -0,0 +1,277 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/raster_layer.hpp> + +@interface MGLRasterLayerTests : MGLStyleLayerTests +@end + +@implementation MGLRasterLayerTests + ++ (NSString *)layerType { + return @"raster"; +} + +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLRasterStyleLayer *layer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::RasterLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::RasterLayer>(); + + // raster-brightness-max + { + XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(), + @"raster-brightness-max should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumRasterBrightness; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.maximumRasterBrightness = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue, + @"Setting maximumRasterBrightness to a constant value should update raster-brightness-max."); + XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue, + @"maximumRasterBrightness should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.maximumRasterBrightness = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue, + @"Setting maximumRasterBrightness to a function should update raster-brightness-max."); + XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue, + @"maximumRasterBrightness should round-trip functions."); + + layer.maximumRasterBrightness = nil; + XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(), + @"Unsetting maximumRasterBrightness should return raster-brightness-max to the default value."); + XCTAssertEqualObjects(layer.maximumRasterBrightness, defaultStyleValue, + @"maximumRasterBrightness should return the default value after being unset."); + } + + // raster-brightness-min + { + XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(), + @"raster-brightness-min should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.minimumRasterBrightness; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.minimumRasterBrightness = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue, + @"Setting minimumRasterBrightness to a constant value should update raster-brightness-min."); + XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue, + @"minimumRasterBrightness should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.minimumRasterBrightness = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue, + @"Setting minimumRasterBrightness to a function should update raster-brightness-min."); + XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue, + @"minimumRasterBrightness should round-trip functions."); + + layer.minimumRasterBrightness = nil; + XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(), + @"Unsetting minimumRasterBrightness should return raster-brightness-min to the default value."); + XCTAssertEqualObjects(layer.minimumRasterBrightness, defaultStyleValue, + @"minimumRasterBrightness should return the default value after being unset."); + } + + // raster-contrast + { + XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(), + @"raster-contrast should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterContrast; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.rasterContrast = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue, + @"Setting rasterContrast to a constant value should update raster-contrast."); + XCTAssertEqualObjects(layer.rasterContrast, styleValue, + @"rasterContrast should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.rasterContrast = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue, + @"Setting rasterContrast to a function should update raster-contrast."); + XCTAssertEqualObjects(layer.rasterContrast, styleValue, + @"rasterContrast should round-trip functions."); + + layer.rasterContrast = nil; + XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(), + @"Unsetting rasterContrast should return raster-contrast to the default value."); + XCTAssertEqualObjects(layer.rasterContrast, defaultStyleValue, + @"rasterContrast should return the default value after being unset."); + } + + // raster-fade-duration + { + XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(), + @"raster-fade-duration should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterFadeDuration; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.rasterFadeDuration = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue, + @"Setting rasterFadeDuration to a constant value should update raster-fade-duration."); + XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue, + @"rasterFadeDuration should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.rasterFadeDuration = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue, + @"Setting rasterFadeDuration to a function should update raster-fade-duration."); + XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue, + @"rasterFadeDuration should round-trip functions."); + + layer.rasterFadeDuration = nil; + XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(), + @"Unsetting rasterFadeDuration should return raster-fade-duration to the default value."); + XCTAssertEqualObjects(layer.rasterFadeDuration, defaultStyleValue, + @"rasterFadeDuration should return the default value after being unset."); + } + + // raster-hue-rotate + { + XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(), + @"raster-hue-rotate should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterHueRotation; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.rasterHueRotation = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue, + @"Setting rasterHueRotation to a constant value should update raster-hue-rotate."); + XCTAssertEqualObjects(layer.rasterHueRotation, styleValue, + @"rasterHueRotation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.rasterHueRotation = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue, + @"Setting rasterHueRotation to a function should update raster-hue-rotate."); + XCTAssertEqualObjects(layer.rasterHueRotation, styleValue, + @"rasterHueRotation should round-trip functions."); + + layer.rasterHueRotation = nil; + XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(), + @"Unsetting rasterHueRotation should return raster-hue-rotate to the default value."); + XCTAssertEqualObjects(layer.rasterHueRotation, defaultStyleValue, + @"rasterHueRotation should return the default value after being unset."); + } + + // raster-opacity + { + XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(), + @"raster-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.rasterOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue, + @"Setting rasterOpacity to a constant value should update raster-opacity."); + XCTAssertEqualObjects(layer.rasterOpacity, styleValue, + @"rasterOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.rasterOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue, + @"Setting rasterOpacity to a function should update raster-opacity."); + XCTAssertEqualObjects(layer.rasterOpacity, styleValue, + @"rasterOpacity should round-trip functions."); + + layer.rasterOpacity = nil; + XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(), + @"Unsetting rasterOpacity should return raster-opacity to the default value."); + XCTAssertEqualObjects(layer.rasterOpacity, defaultStyleValue, + @"rasterOpacity should return the default value after being unset."); + } + + // raster-saturation + { + XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(), + @"raster-saturation should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterSaturation; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.rasterSaturation = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue, + @"Setting rasterSaturation to a constant value should update raster-saturation."); + XCTAssertEqualObjects(layer.rasterSaturation, styleValue, + @"rasterSaturation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.rasterSaturation = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue, + @"Setting rasterSaturation to a function should update raster-saturation."); + XCTAssertEqualObjects(layer.rasterSaturation, styleValue, + @"rasterSaturation should round-trip functions."); + + layer.rasterSaturation = nil; + XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(), + @"Unsetting rasterSaturation should return raster-saturation to the default value."); + XCTAssertEqualObjects(layer.rasterSaturation, defaultStyleValue, + @"rasterSaturation should return the default value after being unset."); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"maximum-raster-brightness" isBoolean:NO]; + [self testPropertyName:@"minimum-raster-brightness" isBoolean:NO]; + [self testPropertyName:@"raster-contrast" isBoolean:NO]; + [self testPropertyName:@"raster-fade-duration" isBoolean:NO]; + [self testPropertyName:@"raster-hue-rotation" isBoolean:NO]; + [self testPropertyName:@"raster-opacity" isBoolean:NO]; + [self testPropertyName:@"raster-saturation" isBoolean:NO]; +} + +@end diff --git a/platform/darwin/test/MGLRuntimeStylingHelper.h b/platform/darwin/test/MGLRuntimeStylingHelper.h deleted file mode 100644 index 8857dba9c5..0000000000 --- a/platform/darwin/test/MGLRuntimeStylingHelper.h +++ /dev/null @@ -1,35 +0,0 @@ -#import <Foundation/Foundation.h> - -#import "MGLTypes.h" -#import "MGLStyleValue.h" - -@interface MGLRuntimeStylingHelper : NSObject - -+ (MGLStyleConstantValue<NSValue *> *)testPadding; -+ (MGLStyleFunction<NSValue *> *)testPaddingFunction; - -+ (MGLStyleConstantValue<NSValue *> *)testOffset; -+ (MGLStyleFunction<NSValue *> *)testOffsetFunction; - -+ (MGLStyleConstantValue<NSArray<NSString *> *> *)testFont; -+ (MGLStyleFunction<NSArray<NSString *> *> *)testFontFunction; - -+ (MGLStyleConstantValue<NSArray<NSNumber *> *> *)testDashArray; -+ (MGLStyleFunction<NSArray<NSNumber *> *> *)testDashArrayFunction; - -+ (MGLStyleConstantValue<NSNumber *> *)testNumber; -+ (MGLStyleFunction<NSNumber *> *)testNumberFunction; - -+ (MGLStyleConstantValue<NSNumber *> *)testBool; -+ (MGLStyleFunction<NSNumber *> *)testBoolFunction; - -+ (MGLStyleConstantValue<NSString *> *)testString; -+ (MGLStyleFunction<NSString *> *)testStringFunction; - -+ (MGLStyleConstantValue<MGLColor *> *)testColor; -+ (MGLStyleFunction<MGLColor *> *)testColorFunction; - -+ (MGLStyleConstantValue<NSValue *> *)testEnum:(NSUInteger)value type:(const char *)type; -+ (MGLStyleFunction<NSValue *> *)testEnumFunction:(NSUInteger)value type:(const char *)type; - -@end diff --git a/platform/darwin/test/MGLRuntimeStylingHelper.m b/platform/darwin/test/MGLRuntimeStylingHelper.m deleted file mode 100644 index 955c664f2c..0000000000 --- a/platform/darwin/test/MGLRuntimeStylingHelper.m +++ /dev/null @@ -1,122 +0,0 @@ -#import "MGLRuntimeStylingHelper.h" - -#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - #import <UIKit/UIKit.h> - #define MGLEdgeInsets UIEdgeInsets -#else - #import <Cocoa/Cocoa.h> - #define MGLEdgeInsets NSEdgeInsets -#endif - -@implementation MGLRuntimeStylingHelper - -+ (MGLStyleConstantValue<NSValue *> *)testPadding -{ - MGLEdgeInsets insets = { - .top = 1, - .left = 1, - .bottom = 1, - .right = 1, - }; - return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&insets withObjCType:@encode(MGLEdgeInsets)]]; -} - -+ (MGLStyleFunction<NSValue *> *)testPaddingFunction -{ - return [MGLStyleFunction<NSValue *> functionWithStops:@{@(18): self.testPadding}]; -} - -+ (MGLStyleConstantValue<NSValue *> *)testOffset -{ - CGVector vector = CGVectorMake(1, 1); - return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&vector withObjCType:@encode(CGVector)]]; -} - -+ (MGLStyleFunction<NSValue *> *)testOffsetFunction -{ - return [MGLStyleFunction<NSValue *> valueWithStops:@{ @(18): self.testOffset }]; -} - -+ (MGLStyleConstantValue<NSArray<NSString *> *> *)testFont -{ - return [MGLStyleConstantValue<NSArray<NSString *> *> valueWithRawValue:@[@"Open Sans Regular", @"Arial Unicode MS Regular"]]; -} - -+ (MGLStyleFunction<NSArray<NSString *> *> *)testFontFunction -{ - return [MGLStyleFunction<NSArray<NSString *> *> valueWithStops:@{ @18: self.testFont }]; -} - -+ (MGLStyleConstantValue<NSArray<NSNumber *> *> *)testDashArray -{ - return [MGLStyleConstantValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]]; -} - -+ (MGLStyleFunction<NSArray<NSNumber *> *> *)testDashArrayFunction -{ - return [MGLStyleFunction<NSArray<NSNumber *> *> valueWithStops:@{ - @18: self.testDashArray, - }]; -} - -+ (MGLStyleConstantValue<NSNumber *> *)testNumber -{ - return [MGLStyleConstantValue<NSNumber *> valueWithRawValue:@1]; -} - -+ (MGLStyleFunction<NSNumber *> *)testNumberFunction -{ - return [MGLStyleFunction<NSNumber *> valueWithStops:@{ - @18: self.testNumber, - }]; -} - -+ (MGLStyleConstantValue<NSNumber *> *)testBool -{ - return [MGLStyleConstantValue<NSNumber *> valueWithRawValue:@YES]; -} - -+ (MGLStyleFunction<NSNumber *> *)testBoolFunction -{ - return [MGLStyleFunction<NSNumber *> valueWithStops:@{ - @18: self.testBool, - }]; -} - -+ (MGLStyleConstantValue<NSString *> *)testString -{ - return [MGLStyleConstantValue<NSString *> valueWithRawValue:@"test"]; -} - -+ (MGLStyleFunction<NSString *> *)testStringFunction -{ - return [MGLStyleFunction<NSString *> valueWithStops:@{ - @18: self.testString, - }]; -} - -+ (MGLStyleConstantValue<MGLColor *> *)testColor -{ - return [MGLStyleConstantValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; -} - -+ (MGLStyleFunction<MGLColor *> *)testColorFunction -{ - return [MGLStyleFunction<MGLColor *> valueWithStops:@{ - @18: self.testColor, - }]; -} - -+ (MGLStyleConstantValue<NSValue *> *)testEnum:(NSUInteger)value type:(const char *)type -{ - return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&value withObjCType:type]]; -} - -+ (MGLStyleFunction<NSValue *> *)testEnumFunction:(NSUInteger)value type:(const char *)type -{ - return [MGLStyleFunction<NSValue *> valueWithStops:@{ - @18: [self testEnum:value type:type], - }]; -} - -@end diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm index efff4b393e..cf32b5c821 100644 --- a/platform/darwin/test/MGLShapeSourceTests.mm +++ b/platform/darwin/test/MGLShapeSourceTests.mm @@ -37,6 +37,19 @@ XCTAssertNil(source.shape); } +- (void)testUnclusterableShape { + NSDictionary *options = @{ + MGLShapeSourceOptionClustered: @YES, + }; + + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:[[MGLPointFeature alloc] init] options:options]; + XCTAssertTrue([source.shape isKindOfClass:[MGLPointFeature class]]); + + MGLShapeCollectionFeature *feature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[]]; + source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:feature options:options]; + XCTAssertTrue([source.shape isKindOfClass:[MGLShapeCollectionFeature class]]); +} + - (void)testMGLShapeSourceWithDataMultipleFeatures { NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-104.34814453125,37.64903402157866]]}}]}"; @@ -265,4 +278,43 @@ XCTAssert(shape.shapes.count == 6, @"Shape collection should contain 6 shapes"); } +- (void)testMGLShapeSourceWithFeaturesConvenienceInitializer { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(100.0, 0.0), + CLLocationCoordinate2DMake(101.0, 0.0), + CLLocationCoordinate2DMake(101.0, 1.0), + CLLocationCoordinate2DMake(100.0, 1.0), + CLLocationCoordinate2DMake(100.0, 0.0)}; + + MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil]; + + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil]; + MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape; + + XCTAssertTrue([shape isKindOfClass:[MGLShapeCollectionFeature class]]); + XCTAssertEqual(shape.shapes.count, 1, @"Shape collection should contain 1 shape"); + + // when a shape is included in the features array + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil]; + + XCTAssertThrowsSpecificNamed([[MGLShapeSource alloc] initWithIdentifier:@"source-id-invalid" features:@[polygon] options:nil], NSException, NSInvalidArgumentException, @"Shape source should raise an exception if a shape is sent to the features initializer"); +} + +- (void)testMGLShapeSourceWithShapesConvenienceInitializer { + CLLocationCoordinate2D coordinates[] = { + CLLocationCoordinate2DMake(100.0, 0.0), + CLLocationCoordinate2DMake(101.0, 0.0), + CLLocationCoordinate2DMake(101.0, 1.0), + CLLocationCoordinate2DMake(100.0, 1.0), + CLLocationCoordinate2DMake(100.0, 0.0)}; + + MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil]; + + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shapes:@[polygon] options:nil]; + MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape; + + XCTAssertTrue([shape isKindOfClass:[MGLShapeCollection class]]); + XCTAssertEqual(shape.shapes.count, 1, @"Shape collection should contain 1 shape"); +} + @end diff --git a/platform/darwin/test/MGLStyleLayerTests.h b/platform/darwin/test/MGLStyleLayerTests.h index 74ce62e894..f0b889f022 100644 --- a/platform/darwin/test/MGLStyleLayerTests.h +++ b/platform/darwin/test/MGLStyleLayerTests.h @@ -1,11 +1,8 @@ #import <Mapbox/Mapbox.h> -#import "MGLRuntimeStylingHelper.h" #import <XCTest/XCTest.h> @interface MGLStyleLayerTests : XCTestCase <MGLMapViewDelegate> -@property (nonatomic) IBOutlet MGLMapView *mapView; -@property (nonatomic) XCTestExpectation *expectation; @property (nonatomic, copy, readonly, class) NSString *layerType; - (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean; @@ -18,3 +15,11 @@ @property (nonatomic, readonly, copy) NSString *lemma; @end + +@interface NSValue (MGLStyleLayerTestAdditions) + ++ (instancetype)valueWithMGLVector:(CGVector)vector; + +@property (readonly) CGVector MGLVectorValue; + +@end diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m index 590d6eda7f..1dba9f4305 100644 --- a/platform/darwin/test/MGLStyleLayerTests.m +++ b/platform/darwin/test/MGLStyleLayerTests.m @@ -8,21 +8,28 @@ @dynamic layerType; -- (void)setUp { - [super setUp]; -#if TARGET_OS_IPHONE - UIApplication *app = [UIApplication sharedApplication]; - UIViewController *vc = [[UIViewController alloc] init]; - app.keyWindow.rootViewController = vc; - [vc view]; // Force load xib - _mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 256, 256)]; - [vc.view addSubview:_mapView]; - _mapView.delegate = self; -#else - [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; - NSWindowController *windowController = [[NSWindowController alloc] initWithWindowNibName:@"MGLStyleLayerTests" owner:self]; - [windowController showWindow:nil]; -#endif +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertEqualObjects(layer.identifier, @"layerID"); + XCTAssertEqualObjects(layer.sourceIdentifier, source.identifier); + + XCTAssertTrue(layer.visible); + layer.visible = NO; + XCTAssertFalse(layer.visible); + layer.visible = YES; + XCTAssertTrue(layer.visible); + + XCTAssertEqual(layer.minimumZoomLevel, -INFINITY); + layer.minimumZoomLevel = 22; + XCTAssertEqual(layer.minimumZoomLevel, 22); + + XCTAssertEqual(layer.maximumZoomLevel, INFINITY); + layer.maximumZoomLevel = 0; + XCTAssertEqual(layer.maximumZoomLevel, 0); } - (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean { @@ -87,3 +94,25 @@ } @end + +@implementation NSValue (MGLStyleLayerTestAdditions) + ++ (instancetype)valueWithMGLVector:(CGVector)vector { +#if TARGET_OS_IPHONE + return [self valueWithCGVector:vector]; +#else + return [self value:&vector withObjCType:@encode(CGVector)]; +#endif +} + +- (CGVector)MGLVectorValue { +#if TARGET_OS_IPHONE + return self.CGVectorValue; +#else + CGVector vector; + [self getValue:&vector]; + return vector; +#endif +} + +@end diff --git a/platform/darwin/test/MGLStyleLayerTests.m.ejs b/platform/darwin/test/MGLStyleLayerTests.m.ejs deleted file mode 100644 index 6b7bfe2f1c..0000000000 --- a/platform/darwin/test/MGLStyleLayerTests.m.ejs +++ /dev/null @@ -1,72 +0,0 @@ -<% - const type = locals.type; - const layoutProperties = locals.layoutProperties; - const paintProperties = locals.paintProperties; --%> -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests -@end - -@implementation MGL<%- camelize(type) %>LayerTests - -+ (NSString *)layerType { - return @"<%- type %>"; -} - -- (void)test<%- camelize(type) %>Layer { -<% if (type === 'background') { -%> - MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID"]; -<% } else { -%> - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source]; -<% } -%> - [self.mapView.style addLayer:layer]; - -<% for (const property of layoutProperties) { -%> - <%- testImplementation(property, type) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testImplementation(property, type) %> -<% } -%> - - MGL<%- camelize(type) %>StyleLayer *gLayer = (MGL<%- camelize(type) %>StyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGL<%- camelize(type) %>StyleLayer class]]); -<% for (const property of layoutProperties) { -%> - <%- testGetterImplementation(property, type) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testGetterImplementation(property, type) %> -<% } -%> - -<% for (const property of layoutProperties) { -%> - <%- testImplementation(property, type, true) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testImplementation(property, type, true) %> -<% } -%> - -<% for (const property of layoutProperties) { -%> - <%- testGetterImplementation(property, type, true) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testGetterImplementation(property, type, true) %> -<% } -%> -} - -- (void)testPropertyNames { -<% for (const property of layoutProperties) { -%> - [self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>]; -<% } -%> -<% for (const property of paintProperties) { -%> - [self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>]; -<% } -%> -} - -@end diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs new file mode 100644 index 0000000000..00842a5b4e --- /dev/null +++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs @@ -0,0 +1,114 @@ +<% + const type = locals.type; + const properties = locals.properties; + const enumProperties = locals.enumProperties; +-%> +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/<%- type %>_layer.hpp> + +@interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests +@end + +@implementation MGL<%- camelize(type) %>LayerTests + ++ (NSString *)layerType { + return @"<%- type %>"; +} + +<% if (type !== 'background' && type !== 'raster') { -%> +- (void)testPredicates { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertNil(layer.sourceLayerIdentifier); + layer.sourceLayerIdentifier = @"layerID"; + XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID"); + layer.sourceLayerIdentifier = nil; + XCTAssertNil(layer.sourceLayerIdentifier); + + XCTAssertNil(layer.predicate); + layer.predicate = [NSPredicate predicateWithValue:NO]; + XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]); + layer.predicate = nil; + XCTAssertNil(layer.predicate); +} + +<% } -%> +- (void)testProperties { +<% if (type === 'background') { -%> + MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID"]; +<% } else { -%> + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source]; +<% } -%> + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::<%- camelize(type) %>Layer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::<%- camelize(type) %>Layer>(); +<% for (const property of properties) { -%> + + // <%- originalPropertyName(property) %> + { + XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(), + @"<%- originalPropertyName(property) %> should be unset initially."); + MGLStyleValue<<%- propertyType(property) %>> *defaultStyleValue = layer.<%- objCName(property) %>; + + MGLStyleValue<<%- propertyType(property) %>> *styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>]; + layer.<%- objCName(property) %> = styleValue; + mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> }; + XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue, + @"Setting <%- objCName(property) %> to a constant value should update <%- originalPropertyName(property) %>."); + XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue, + @"<%- objCName(property) %> should round-trip constant values."); + + styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithStops:@{ + @18: styleValue, + }]; + layer.<%- objCName(property) %> = styleValue; + propertyValue = { mbgl::style::Function<<%- mbglType(property) %>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue, + @"Setting <%- objCName(property) %> to a function should update <%- originalPropertyName(property) %>."); + XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue, + @"<%- objCName(property) %> should round-trip functions."); +<% if (!property.required) { -%> + + layer.<%- objCName(property) %> = nil; + XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(), + @"Unsetting <%- objCName(property) %> should return <%- originalPropertyName(property) %> to the default value."); + XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultStyleValue, + @"<%- objCName(property) %> should return the default value after being unset."); +<% } -%> + } +<% } -%> +} + +- (void)testPropertyNames { +<% for (const property of properties) { -%> + [self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>]; +<% } -%> +} + +<% if (enumProperties) { -%> +- (void)testValueAdditions { +<% for (let property of enumProperties) { -%> +<% for (let value in property.values) { -%> +<% if (property.values.hasOwnProperty(value)) { -%> + XCTAssertEqual([NSValue valueWithMGL<%- camelize(property.name) %>:MGL<%- camelize(property.name) %><%- camelize(value) %>].MGL<%- camelize(property.name) %>Value, MGL<%- camelize(property.name) %><%- camelize(value) %>); +<% } -%> +<% } -%> +<% } -%> +} + +<% } -%> +@end diff --git a/platform/darwin/test/MGLStyleLayerTests.xib b/platform/darwin/test/MGLStyleLayerTests.xib deleted file mode 100644 index 23ad22e7e3..0000000000 --- a/platform/darwin/test/MGLStyleLayerTests.xib +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16A304a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> - <dependencies> - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/> - </dependencies> - <objects> - <customObject id="-2" userLabel="File's Owner" customClass="MGLStyleLayerTests"> - <connections> - <outlet property="mapView" destination="6RL-d9-juy" id="0ch-aR-Um6"/> - </connections> - </customObject> - <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> - <customObject id="-3" userLabel="Application" customClass="NSObject"/> - <window title="MGLStyleLayerTests" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g"> - <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> - <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="196" y="240" width="256" height="256"/> - <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1058"/> - <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ"> - <rect key="frame" x="0.0" y="0.0" width="256" height="256"/> - <autoresizingMask key="autoresizingMask"/> - <subviews> - <customView translatesAutoresizingMaskIntoConstraints="NO" id="6RL-d9-juy" customClass="MGLMapView"> - <rect key="frame" x="0.0" y="0.0" width="256" height="256"/> - <connections> - <outlet property="delegate" destination="-2" id="6kS-ct-JEg"/> - </connections> - </customView> - </subviews> - <constraints> - <constraint firstItem="6RL-d9-juy" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="KEN-aL-UF0"/> - <constraint firstAttribute="bottom" secondItem="6RL-d9-juy" secondAttribute="bottom" id="V27-f3-xHZ"/> - <constraint firstAttribute="trailing" secondItem="6RL-d9-juy" secondAttribute="trailing" id="vjq-iM-OyA"/> - <constraint firstItem="6RL-d9-juy" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="yWg-v4-wJB"/> - </constraints> - </view> - </window> - </objects> -</document> diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm index e9ba4a9afa..176217619d 100644 --- a/platform/darwin/test/MGLStyleTests.mm +++ b/platform/darwin/test/MGLStyleTests.mm @@ -1,17 +1,4 @@ -#import "MGLMapView.h" -#import "MGLStyle_Private.h" - -#import "MGLShapeSource.h" -#import "MGLRasterSource.h" -#import "MGLVectorSource.h" - -#import "MGLBackgroundStyleLayer.h" -#import "MGLCircleStyleLayer.h" -#import "MGLFillStyleLayer.h" -#import "MGLLineStyleLayer.h" -#import "MGLOpenGLStyleLayer.h" -#import "MGLRasterStyleLayer.h" -#import "MGLSymbolStyleLayer.h" +#import <Mapbox/Mapbox.h> #import "NSBundle+MGLAdditions.h" @@ -25,20 +12,46 @@ #endif #import <objc/runtime.h> -@interface MGLStyleTests : XCTestCase +@interface MGLStyleTests : XCTestCase <MGLMapViewDelegate> @property (nonatomic) MGLMapView *mapView; @property (nonatomic) MGLStyle *style; @end -@implementation MGLStyleTests +@implementation MGLStyleTests { + XCTestExpectation *_styleLoadingExpectation; +} - (void)setUp { [super setUp]; + + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; + NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) styleURL:styleURL]; + self.mapView.delegate = self; + if (!self.mapView.style) { + _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; + [self waitForExpectationsWithTimeout:1 handler:nil]; + } +} - self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; - self.style = [[MGLStyle alloc] initWithMapView:self.mapView]; +- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { + XCTAssertNotNil(mapView.style); + XCTAssertEqual(mapView.style, style); + + [_styleLoadingExpectation fulfill]; +} + +- (void)tearDown { + _styleLoadingExpectation = nil; + self.mapView = nil; + + [super tearDown]; +} + +- (MGLStyle *)style { + return self.mapView.style; } - (void)testUnversionedStyleURLs { @@ -121,6 +134,24 @@ }]; } +- (void)testName { + XCTAssertNil(self.style.name); +} + +- (void)testSources { + NSSet<MGLSource *> *initialSources = self.style.sources; + if ([initialSources.anyObject.identifier isEqualToString:@"com.mapbox.annotations"]) { + XCTAssertEqual(self.style.sources.count, 1); + } else { + XCTAssertEqual(self.style.sources.count, 0); + } + MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil]; + [self.style addSource:shapeSource]; + XCTAssertEqual(self.style.sources.count, initialSources.count + 1); + [self.style removeSource:shapeSource]; + XCTAssertEqual(self.style.sources.count, initialSources.count); +} + - (void)testAddingSourcesTwice { MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil]; [self.style addSource:shapeSource]; @@ -143,6 +174,22 @@ XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentifierException"); } +- (void)testLayers { + NSArray<MGLStyleLayer *> *initialLayers = self.style.layers; + if ([initialLayers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) { + XCTAssertEqual(self.style.layers.count, 1); + } else { + XCTAssertEqual(self.style.layers.count, 0); + } + MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil]; + [self.style addSource:shapeSource]; + MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:shapeSource]; + [self.style addLayer:fillLayer]; + XCTAssertEqual(self.style.layers.count, initialLayers.count + 1); + [self.style removeLayer:fillLayer]; + XCTAssertEqual(self.style.layers.count, initialLayers.count); +} + - (void)testAddingLayersTwice { MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil]; @@ -174,18 +221,18 @@ - (void)testAddingLayersWithDuplicateIdentifiers { //Just some source MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]]; - [self.mapView.style addSource: source]; + [self.style addSource: source]; //Add initial layer MGLFillStyleLayer *initial = [[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]; - [self.mapView.style addLayer:initial]; + [self.style addLayer:initial]; //Try to add the duplicate - XCTAssertThrowsSpecificNamed([self.mapView.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); } - (NSString *)stringWithContentsOfStyleHeader { @@ -198,6 +245,10 @@ return styleHeader; } +- (void)testClasses { + XCTAssertEqual(self.style.styleClasses.count, 0); +} + - (void)testImages { NSString *imageName = @"TrackingLocationMask"; #if TARGET_OS_IPHONE @@ -209,12 +260,46 @@ #endif XCTAssertNotNil(image); - [self.mapView.style setImage:image forName:imageName]; - MGLImage *styleImage = [self.mapView.style imageForName:imageName]; + [self.style setImage:image forName:imageName]; + MGLImage *styleImage = [self.style imageForName:imageName]; XCTAssertNotNil(styleImage); XCTAssertEqual(image.size.width, styleImage.size.width); XCTAssertEqual(image.size.height, styleImage.size.height); } +- (void)testLayersOrder { + NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; + NSURL *url = [NSURL fileURLWithPath:filePath]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; + [self.style addSource:source]; + + MGLCircleStyleLayer *layer1 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer1" source:source]; + [self.style addLayer:layer1]; + + MGLCircleStyleLayer *layer3 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer3" source:source]; + [self.style addLayer:layer3]; + + MGLCircleStyleLayer *layer2 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer2" source:source]; + [self.style insertLayer:layer2 aboveLayer:layer1]; + + MGLCircleStyleLayer *layer4 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer4" source:source]; + [self.style insertLayer:layer4 aboveLayer:layer3]; + + MGLCircleStyleLayer *layer0 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer0" source:source]; + [self.style insertLayer:layer0 belowLayer:layer1]; + + NSArray<MGLStyleLayer *> *layers = [self.style layers]; + NSUInteger startIndex = 0; + if ([layers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) { + startIndex++; + } + + XCTAssertEqualObjects(layers[startIndex++].identifier, layer0.identifier); + XCTAssertEqualObjects(layers[startIndex++].identifier, layer1.identifier); + XCTAssertEqualObjects(layers[startIndex++].identifier, layer2.identifier); + XCTAssertEqualObjects(layers[startIndex++].identifier, layer3.identifier); + XCTAssertEqualObjects(layers[startIndex++].identifier, layer4.identifier); +} + @end diff --git a/platform/darwin/test/MGLStyleValueTests.swift b/platform/darwin/test/MGLStyleValueTests.swift index bf01435114..18b6a901de 100644 --- a/platform/darwin/test/MGLStyleValueTests.swift +++ b/platform/darwin/test/MGLStyleValueTests.swift @@ -17,8 +17,8 @@ extension MGLStyleValueTests { XCTAssertEqual((symbolStyleLayer.iconHaloWidth as! MGLStyleConstantValue<NSNumber>).rawValue, 3) // String - symbolStyleLayer.textField = MGLStyleConstantValue(rawValue: "{name}") - XCTAssertEqual((symbolStyleLayer.textField as! MGLStyleConstantValue<NSString>).rawValue, "{name}") + symbolStyleLayer.text = MGLStyleConstantValue(rawValue: "{name}") + XCTAssertEqual((symbolStyleLayer.text as! MGLStyleConstantValue<NSString>).rawValue, "{name}") } func testFunctions() { @@ -32,7 +32,7 @@ extension MGLStyleValueTests { 3: MGLStyleValue(rawValue: true), 4: MGLStyleValue(rawValue: false), ] - symbolStyleLayer.iconAllowsOverlap = MGLStyleFunction<NSNumber>(base: 1, stops: stops) - XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLStyleFunction<NSNumber>), MGLStyleFunction(base: 1, stops: stops)) + symbolStyleLayer.iconAllowsOverlap = MGLStyleFunction<NSNumber>(interpolationBase: 1, stops: stops) + XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLStyleFunction<NSNumber>), MGLStyleFunction(interpolationBase: 1, stops: stops)) } } diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.m b/platform/darwin/test/MGLSymbolStyleLayerTests.m deleted file mode 100644 index 40250a8c72..0000000000 --- a/platform/darwin/test/MGLSymbolStyleLayerTests.m +++ /dev/null @@ -1,283 +0,0 @@ -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGLSymbolLayerTests : MGLStyleLayerTests -@end - -@implementation MGLSymbolLayerTests - -+ (NSString *)layerType { - return @"symbol"; -} - -- (void)testSymbolLayer { - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; - [self.mapView.style addLayer:layer]; - - layer.iconAllowsOverlap = [MGLRuntimeStylingHelper testBool]; - layer.iconIgnoresPlacement = [MGLRuntimeStylingHelper testBool]; - layer.iconImageName = [MGLRuntimeStylingHelper testString]; - layer.iconOffset = [MGLRuntimeStylingHelper testOffset]; - layer.iconOptional = [MGLRuntimeStylingHelper testBool]; - layer.iconPadding = [MGLRuntimeStylingHelper testNumber]; - layer.iconRotation = [MGLRuntimeStylingHelper testNumber]; - layer.iconRotationAlignment = [MGLRuntimeStylingHelper testEnum:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)]; - layer.iconScale = [MGLRuntimeStylingHelper testNumber]; - layer.iconTextFit = [MGLRuntimeStylingHelper testEnum:MGLIconTextFitBoth type:@encode(MGLIconTextFit)]; - layer.iconTextFitPadding = [MGLRuntimeStylingHelper testPadding]; - layer.keepsIconUpright = [MGLRuntimeStylingHelper testBool]; - layer.keepsTextUpright = [MGLRuntimeStylingHelper testBool]; - layer.maximumTextAngle = [MGLRuntimeStylingHelper testNumber]; - layer.maximumTextWidth = [MGLRuntimeStylingHelper testNumber]; - layer.symbolAvoidsEdges = [MGLRuntimeStylingHelper testBool]; - layer.symbolPlacement = [MGLRuntimeStylingHelper testEnum:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)]; - layer.symbolSpacing = [MGLRuntimeStylingHelper testNumber]; - layer.textAllowsOverlap = [MGLRuntimeStylingHelper testBool]; - layer.textAnchor = [MGLRuntimeStylingHelper testEnum:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)]; - layer.textField = [MGLRuntimeStylingHelper testString]; - layer.textFont = [MGLRuntimeStylingHelper testFont]; - layer.textIgnoresPlacement = [MGLRuntimeStylingHelper testBool]; - layer.textJustification = [MGLRuntimeStylingHelper testEnum:MGLTextJustificationRight type:@encode(MGLTextJustification)]; - layer.textLetterSpacing = [MGLRuntimeStylingHelper testNumber]; - layer.textLineHeight = [MGLRuntimeStylingHelper testNumber]; - layer.textOffset = [MGLRuntimeStylingHelper testOffset]; - layer.textOptional = [MGLRuntimeStylingHelper testBool]; - layer.textPadding = [MGLRuntimeStylingHelper testNumber]; - layer.textPitchAlignment = [MGLRuntimeStylingHelper testEnum:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)]; - layer.textRotation = [MGLRuntimeStylingHelper testNumber]; - layer.textRotationAlignment = [MGLRuntimeStylingHelper testEnum:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)]; - layer.textSize = [MGLRuntimeStylingHelper testNumber]; - layer.textTransform = [MGLRuntimeStylingHelper testEnum:MGLTextTransformLowercase type:@encode(MGLTextTransform)]; - layer.iconColor = [MGLRuntimeStylingHelper testColor]; - layer.iconHaloBlur = [MGLRuntimeStylingHelper testNumber]; - layer.iconHaloColor = [MGLRuntimeStylingHelper testColor]; - layer.iconHaloWidth = [MGLRuntimeStylingHelper testNumber]; - layer.iconOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.iconTranslate = [MGLRuntimeStylingHelper testOffset]; - layer.iconTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)]; - layer.textColor = [MGLRuntimeStylingHelper testColor]; - layer.textHaloBlur = [MGLRuntimeStylingHelper testNumber]; - layer.textHaloColor = [MGLRuntimeStylingHelper testColor]; - layer.textHaloWidth = [MGLRuntimeStylingHelper testNumber]; - layer.textOpacity = [MGLRuntimeStylingHelper testNumber]; - layer.textTranslate = [MGLRuntimeStylingHelper testOffset]; - layer.textTranslateAnchor = [MGLRuntimeStylingHelper testEnum:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)]; - - MGLSymbolStyleLayer *gLayer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGLSymbolStyleLayer class]]); - XCTAssertEqualObjects(gLayer.iconAllowsOverlap, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.iconIgnoresPlacement, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.iconImageName, [MGLRuntimeStylingHelper testString]); - XCTAssertEqualObjects(gLayer.iconOffset, [MGLRuntimeStylingHelper testOffset]); - XCTAssertEqualObjects(gLayer.iconOptional, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.iconPadding, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.iconRotation, [MGLRuntimeStylingHelper testNumber]); - XCTAssert([gLayer.iconRotationAlignment isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.iconRotationAlignment, [MGLRuntimeStylingHelper testEnum:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)]); - XCTAssertEqualObjects(gLayer.iconScale, [MGLRuntimeStylingHelper testNumber]); - XCTAssert([gLayer.iconTextFit isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.iconTextFit, [MGLRuntimeStylingHelper testEnum:MGLIconTextFitBoth type:@encode(MGLIconTextFit)]); - XCTAssertEqualObjects(gLayer.iconTextFitPadding, [MGLRuntimeStylingHelper testPadding]); - XCTAssertEqualObjects(gLayer.keepsIconUpright, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.keepsTextUpright, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.maximumTextAngle, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.maximumTextWidth, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.symbolAvoidsEdges, [MGLRuntimeStylingHelper testBool]); - XCTAssert([gLayer.symbolPlacement isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.symbolPlacement, [MGLRuntimeStylingHelper testEnum:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)]); - XCTAssertEqualObjects(gLayer.symbolSpacing, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.textAllowsOverlap, [MGLRuntimeStylingHelper testBool]); - XCTAssert([gLayer.textAnchor isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.textAnchor, [MGLRuntimeStylingHelper testEnum:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)]); - XCTAssertEqualObjects(gLayer.textField, [MGLRuntimeStylingHelper testString]); - XCTAssertEqualObjects(gLayer.textFont, [MGLRuntimeStylingHelper testFont]); - XCTAssertEqualObjects(gLayer.textIgnoresPlacement, [MGLRuntimeStylingHelper testBool]); - XCTAssert([gLayer.textJustification isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.textJustification, [MGLRuntimeStylingHelper testEnum:MGLTextJustificationRight type:@encode(MGLTextJustification)]); - XCTAssertEqualObjects(gLayer.textLetterSpacing, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.textLineHeight, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.textOffset, [MGLRuntimeStylingHelper testOffset]); - XCTAssertEqualObjects(gLayer.textOptional, [MGLRuntimeStylingHelper testBool]); - XCTAssertEqualObjects(gLayer.textPadding, [MGLRuntimeStylingHelper testNumber]); - XCTAssert([gLayer.textPitchAlignment isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.textPitchAlignment, [MGLRuntimeStylingHelper testEnum:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)]); - XCTAssertEqualObjects(gLayer.textRotation, [MGLRuntimeStylingHelper testNumber]); - XCTAssert([gLayer.textRotationAlignment isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.textRotationAlignment, [MGLRuntimeStylingHelper testEnum:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)]); - XCTAssertEqualObjects(gLayer.textSize, [MGLRuntimeStylingHelper testNumber]); - XCTAssert([gLayer.textTransform isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.textTransform, [MGLRuntimeStylingHelper testEnum:MGLTextTransformLowercase type:@encode(MGLTextTransform)]); - XCTAssertEqualObjects(gLayer.iconColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.iconHaloBlur, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.iconHaloColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.iconHaloWidth, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.iconOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.iconTranslate, [MGLRuntimeStylingHelper testOffset]); - XCTAssert([gLayer.iconTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.iconTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)]); - XCTAssertEqualObjects(gLayer.textColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.textHaloBlur, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.textHaloColor, [MGLRuntimeStylingHelper testColor]); - XCTAssertEqualObjects(gLayer.textHaloWidth, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.textOpacity, [MGLRuntimeStylingHelper testNumber]); - XCTAssertEqualObjects(gLayer.textTranslate, [MGLRuntimeStylingHelper testOffset]); - XCTAssert([gLayer.textTranslateAnchor isKindOfClass:[MGLStyleConstantValue class]]); - XCTAssertEqualObjects(gLayer.textTranslateAnchor, [MGLRuntimeStylingHelper testEnum:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)]); - - layer.iconAllowsOverlap = [MGLRuntimeStylingHelper testBoolFunction]; - layer.iconIgnoresPlacement = [MGLRuntimeStylingHelper testBoolFunction]; - layer.iconImageName = [MGLRuntimeStylingHelper testStringFunction]; - layer.iconOffset = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.iconOptional = [MGLRuntimeStylingHelper testBoolFunction]; - layer.iconPadding = [MGLRuntimeStylingHelper testNumberFunction]; - layer.iconRotation = [MGLRuntimeStylingHelper testNumberFunction]; - layer.iconRotationAlignment = [MGLRuntimeStylingHelper testEnumFunction:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)]; - layer.iconScale = [MGLRuntimeStylingHelper testNumberFunction]; - layer.iconTextFit = [MGLRuntimeStylingHelper testEnumFunction:MGLIconTextFitBoth type:@encode(MGLIconTextFit)]; - layer.iconTextFitPadding = [MGLRuntimeStylingHelper testPaddingFunction]; - layer.keepsIconUpright = [MGLRuntimeStylingHelper testBoolFunction]; - layer.keepsTextUpright = [MGLRuntimeStylingHelper testBoolFunction]; - layer.maximumTextAngle = [MGLRuntimeStylingHelper testNumberFunction]; - layer.maximumTextWidth = [MGLRuntimeStylingHelper testNumberFunction]; - layer.symbolAvoidsEdges = [MGLRuntimeStylingHelper testBoolFunction]; - layer.symbolPlacement = [MGLRuntimeStylingHelper testEnumFunction:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)]; - layer.symbolSpacing = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textAllowsOverlap = [MGLRuntimeStylingHelper testBoolFunction]; - layer.textAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)]; - layer.textField = [MGLRuntimeStylingHelper testStringFunction]; - layer.textFont = [MGLRuntimeStylingHelper testFontFunction]; - layer.textIgnoresPlacement = [MGLRuntimeStylingHelper testBoolFunction]; - layer.textJustification = [MGLRuntimeStylingHelper testEnumFunction:MGLTextJustificationRight type:@encode(MGLTextJustification)]; - layer.textLetterSpacing = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textLineHeight = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textOffset = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.textOptional = [MGLRuntimeStylingHelper testBoolFunction]; - layer.textPadding = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textPitchAlignment = [MGLRuntimeStylingHelper testEnumFunction:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)]; - layer.textRotation = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textRotationAlignment = [MGLRuntimeStylingHelper testEnumFunction:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)]; - layer.textSize = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textTransform = [MGLRuntimeStylingHelper testEnumFunction:MGLTextTransformLowercase type:@encode(MGLTextTransform)]; - layer.iconColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.iconHaloBlur = [MGLRuntimeStylingHelper testNumberFunction]; - layer.iconHaloColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.iconHaloWidth = [MGLRuntimeStylingHelper testNumberFunction]; - layer.iconOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.iconTranslate = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.iconTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)]; - layer.textColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.textHaloBlur = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textHaloColor = [MGLRuntimeStylingHelper testColorFunction]; - layer.textHaloWidth = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textOpacity = [MGLRuntimeStylingHelper testNumberFunction]; - layer.textTranslate = [MGLRuntimeStylingHelper testOffsetFunction]; - layer.textTranslateAnchor = [MGLRuntimeStylingHelper testEnumFunction:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)]; - - XCTAssertEqualObjects(gLayer.iconAllowsOverlap, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.iconIgnoresPlacement, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.iconImageName, [MGLRuntimeStylingHelper testStringFunction]); - XCTAssertEqualObjects(gLayer.iconOffset, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.iconOptional, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.iconPadding, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.iconRotation, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.iconRotationAlignment, [MGLRuntimeStylingHelper testEnumFunction:MGLIconRotationAlignmentAuto type:@encode(MGLIconRotationAlignment)]); - XCTAssertEqualObjects(gLayer.iconScale, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.iconTextFit, [MGLRuntimeStylingHelper testEnumFunction:MGLIconTextFitBoth type:@encode(MGLIconTextFit)]); - XCTAssertEqualObjects(gLayer.iconTextFitPadding, [MGLRuntimeStylingHelper testPaddingFunction]); - XCTAssertEqualObjects(gLayer.keepsIconUpright, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.keepsTextUpright, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.maximumTextAngle, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.maximumTextWidth, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.symbolAvoidsEdges, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.symbolPlacement, [MGLRuntimeStylingHelper testEnumFunction:MGLSymbolPlacementLine type:@encode(MGLSymbolPlacement)]); - XCTAssertEqualObjects(gLayer.symbolSpacing, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textAllowsOverlap, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.textAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLTextAnchorBottomRight type:@encode(MGLTextAnchor)]); - XCTAssertEqualObjects(gLayer.textField, [MGLRuntimeStylingHelper testStringFunction]); - XCTAssertEqualObjects(gLayer.textFont, [MGLRuntimeStylingHelper testFontFunction]); - XCTAssertEqualObjects(gLayer.textIgnoresPlacement, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.textJustification, [MGLRuntimeStylingHelper testEnumFunction:MGLTextJustificationRight type:@encode(MGLTextJustification)]); - XCTAssertEqualObjects(gLayer.textLetterSpacing, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textLineHeight, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textOffset, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.textOptional, [MGLRuntimeStylingHelper testBoolFunction]); - XCTAssertEqualObjects(gLayer.textPadding, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textPitchAlignment, [MGLRuntimeStylingHelper testEnumFunction:MGLTextPitchAlignmentAuto type:@encode(MGLTextPitchAlignment)]); - XCTAssertEqualObjects(gLayer.textRotation, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textRotationAlignment, [MGLRuntimeStylingHelper testEnumFunction:MGLTextRotationAlignmentAuto type:@encode(MGLTextRotationAlignment)]); - XCTAssertEqualObjects(gLayer.textSize, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textTransform, [MGLRuntimeStylingHelper testEnumFunction:MGLTextTransformLowercase type:@encode(MGLTextTransform)]); - XCTAssertEqualObjects(gLayer.iconColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.iconHaloBlur, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.iconHaloColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.iconHaloWidth, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.iconOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.iconTranslate, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.iconTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLIconTranslateAnchorViewport type:@encode(MGLIconTranslateAnchor)]); - XCTAssertEqualObjects(gLayer.textColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.textHaloBlur, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textHaloColor, [MGLRuntimeStylingHelper testColorFunction]); - XCTAssertEqualObjects(gLayer.textHaloWidth, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textOpacity, [MGLRuntimeStylingHelper testNumberFunction]); - XCTAssertEqualObjects(gLayer.textTranslate, [MGLRuntimeStylingHelper testOffsetFunction]); - XCTAssertEqualObjects(gLayer.textTranslateAnchor, [MGLRuntimeStylingHelper testEnumFunction:MGLTextTranslateAnchorViewport type:@encode(MGLTextTranslateAnchor)]); -} - -- (void)testPropertyNames { - [self testPropertyName:@"icon-allows-overlap" isBoolean:YES]; - [self testPropertyName:@"icon-ignores-placement" isBoolean:YES]; - [self testPropertyName:@"icon-image-name" isBoolean:NO]; - [self testPropertyName:@"icon-offset" isBoolean:NO]; - [self testPropertyName:@"is-icon-optional" isBoolean:YES]; - [self testPropertyName:@"icon-padding" isBoolean:NO]; - [self testPropertyName:@"icon-rotation" isBoolean:NO]; - [self testPropertyName:@"icon-rotation-alignment" isBoolean:NO]; - [self testPropertyName:@"icon-scale" isBoolean:NO]; - [self testPropertyName:@"icon-text-fit" isBoolean:NO]; - [self testPropertyName:@"icon-text-fit-padding" isBoolean:NO]; - [self testPropertyName:@"keeps-icon-upright" isBoolean:YES]; - [self testPropertyName:@"keeps-text-upright" isBoolean:YES]; - [self testPropertyName:@"maximum-text-angle" isBoolean:NO]; - [self testPropertyName:@"maximum-text-width" isBoolean:NO]; - [self testPropertyName:@"symbol-avoids-edges" isBoolean:YES]; - [self testPropertyName:@"symbol-placement" isBoolean:NO]; - [self testPropertyName:@"symbol-spacing" isBoolean:NO]; - [self testPropertyName:@"text-allows-overlap" isBoolean:YES]; - [self testPropertyName:@"text-anchor" isBoolean:NO]; - [self testPropertyName:@"text-field" isBoolean:NO]; - [self testPropertyName:@"text-font" isBoolean:NO]; - [self testPropertyName:@"text-ignores-placement" isBoolean:YES]; - [self testPropertyName:@"text-justification" isBoolean:NO]; - [self testPropertyName:@"text-letter-spacing" isBoolean:NO]; - [self testPropertyName:@"text-line-height" isBoolean:NO]; - [self testPropertyName:@"text-offset" isBoolean:NO]; - [self testPropertyName:@"is-text-optional" isBoolean:YES]; - [self testPropertyName:@"text-padding" isBoolean:NO]; - [self testPropertyName:@"text-pitch-alignment" isBoolean:NO]; - [self testPropertyName:@"text-rotation" isBoolean:NO]; - [self testPropertyName:@"text-rotation-alignment" isBoolean:NO]; - [self testPropertyName:@"text-size" isBoolean:NO]; - [self testPropertyName:@"text-transform" isBoolean:NO]; - [self testPropertyName:@"icon-color" isBoolean:NO]; - [self testPropertyName:@"icon-halo-blur" isBoolean:NO]; - [self testPropertyName:@"icon-halo-color" isBoolean:NO]; - [self testPropertyName:@"icon-halo-width" isBoolean:NO]; - [self testPropertyName:@"icon-opacity" isBoolean:NO]; - [self testPropertyName:@"icon-translate" isBoolean:NO]; - [self testPropertyName:@"icon-translate-anchor" isBoolean:NO]; - [self testPropertyName:@"text-color" isBoolean:NO]; - [self testPropertyName:@"text-halo-blur" isBoolean:NO]; - [self testPropertyName:@"text-halo-color" isBoolean:NO]; - [self testPropertyName:@"text-halo-width" isBoolean:NO]; - [self testPropertyName:@"text-opacity" isBoolean:NO]; - [self testPropertyName:@"text-translate" isBoolean:NO]; - [self testPropertyName:@"text-translate-anchor" isBoolean:NO]; -} - -@end diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm new file mode 100644 index 0000000000..80a9c9d3ec --- /dev/null +++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm @@ -0,0 +1,1797 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. + +#import "MGLStyleLayerTests.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/symbol_layer.hpp> + +@interface MGLSymbolLayerTests : MGLStyleLayerTests +@end + +@implementation MGLSymbolLayerTests + ++ (NSString *)layerType { + return @"symbol"; +} + +- (void)testPredicates { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertNil(layer.sourceLayerIdentifier); + layer.sourceLayerIdentifier = @"layerID"; + XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID"); + layer.sourceLayerIdentifier = nil; + XCTAssertNil(layer.sourceLayerIdentifier); + + XCTAssertNil(layer.predicate); + layer.predicate = [NSPredicate predicateWithValue:NO]; + XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]); + layer.predicate = nil; + XCTAssertNil(layer.predicate); +} + +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::SymbolLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::SymbolLayer>(); + + // icon-allow-overlap + { + XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(), + @"icon-allow-overlap should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconAllowsOverlap; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.iconAllowsOverlap = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue, + @"Setting iconAllowsOverlap to a constant value should update icon-allow-overlap."); + XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue, + @"iconAllowsOverlap should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconAllowsOverlap = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue, + @"Setting iconAllowsOverlap to a function should update icon-allow-overlap."); + XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue, + @"iconAllowsOverlap should round-trip functions."); + + layer.iconAllowsOverlap = nil; + XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(), + @"Unsetting iconAllowsOverlap should return icon-allow-overlap to the default value."); + XCTAssertEqualObjects(layer.iconAllowsOverlap, defaultStyleValue, + @"iconAllowsOverlap should return the default value after being unset."); + } + + // icon-ignore-placement + { + XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(), + @"icon-ignore-placement should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconIgnoresPlacement; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.iconIgnoresPlacement = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue, + @"Setting iconIgnoresPlacement to a constant value should update icon-ignore-placement."); + XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue, + @"iconIgnoresPlacement should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconIgnoresPlacement = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue, + @"Setting iconIgnoresPlacement to a function should update icon-ignore-placement."); + XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue, + @"iconIgnoresPlacement should round-trip functions."); + + layer.iconIgnoresPlacement = nil; + XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(), + @"Unsetting iconIgnoresPlacement should return icon-ignore-placement to the default value."); + XCTAssertEqualObjects(layer.iconIgnoresPlacement, defaultStyleValue, + @"iconIgnoresPlacement should return the default value after being unset."); + } + + // icon-image + { + XCTAssertTrue(rawLayer->getIconImage().isUndefined(), + @"icon-image should be unset initially."); + MGLStyleValue<NSString *> *defaultStyleValue = layer.iconImageName; + + MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Icon Image"]; + layer.iconImageName = styleValue; + mbgl::style::PropertyValue<std::string> propertyValue = { "Icon Image" }; + XCTAssertEqual(rawLayer->getIconImage(), propertyValue, + @"Setting iconImageName to a constant value should update icon-image."); + XCTAssertEqualObjects(layer.iconImageName, styleValue, + @"iconImageName should round-trip constant values."); + + styleValue = [MGLStyleValue<NSString *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconImageName = styleValue; + propertyValue = { mbgl::style::Function<std::string> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconImage(), propertyValue, + @"Setting iconImageName to a function should update icon-image."); + XCTAssertEqualObjects(layer.iconImageName, styleValue, + @"iconImageName should round-trip functions."); + + layer.iconImageName = nil; + XCTAssertTrue(rawLayer->getIconImage().isUndefined(), + @"Unsetting iconImageName should return icon-image to the default value."); + XCTAssertEqualObjects(layer.iconImageName, defaultStyleValue, + @"iconImageName should return the default value after being unset."); + } + + // icon-offset + { + XCTAssertTrue(rawLayer->getIconOffset().isUndefined(), + @"icon-offset should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconOffset; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.iconOffset = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getIconOffset(), propertyValue, + @"Setting iconOffset to a constant value should update icon-offset."); + XCTAssertEqualObjects(layer.iconOffset, styleValue, + @"iconOffset should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconOffset = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconOffset(), propertyValue, + @"Setting iconOffset to a function should update icon-offset."); + XCTAssertEqualObjects(layer.iconOffset, styleValue, + @"iconOffset should round-trip functions."); + + layer.iconOffset = nil; + XCTAssertTrue(rawLayer->getIconOffset().isUndefined(), + @"Unsetting iconOffset should return icon-offset to the default value."); + XCTAssertEqualObjects(layer.iconOffset, defaultStyleValue, + @"iconOffset should return the default value after being unset."); + } + + // icon-optional + { + XCTAssertTrue(rawLayer->getIconOptional().isUndefined(), + @"icon-optional should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOptional; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.iconOptional = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getIconOptional(), propertyValue, + @"Setting iconOptional to a constant value should update icon-optional."); + XCTAssertEqualObjects(layer.iconOptional, styleValue, + @"iconOptional should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconOptional = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconOptional(), propertyValue, + @"Setting iconOptional to a function should update icon-optional."); + XCTAssertEqualObjects(layer.iconOptional, styleValue, + @"iconOptional should round-trip functions."); + + layer.iconOptional = nil; + XCTAssertTrue(rawLayer->getIconOptional().isUndefined(), + @"Unsetting iconOptional should return icon-optional to the default value."); + XCTAssertEqualObjects(layer.iconOptional, defaultStyleValue, + @"iconOptional should return the default value after being unset."); + } + + // icon-padding + { + XCTAssertTrue(rawLayer->getIconPadding().isUndefined(), + @"icon-padding should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconPadding; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.iconPadding = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getIconPadding(), propertyValue, + @"Setting iconPadding to a constant value should update icon-padding."); + XCTAssertEqualObjects(layer.iconPadding, styleValue, + @"iconPadding should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconPadding = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconPadding(), propertyValue, + @"Setting iconPadding to a function should update icon-padding."); + XCTAssertEqualObjects(layer.iconPadding, styleValue, + @"iconPadding should round-trip functions."); + + layer.iconPadding = nil; + XCTAssertTrue(rawLayer->getIconPadding().isUndefined(), + @"Unsetting iconPadding should return icon-padding to the default value."); + XCTAssertEqualObjects(layer.iconPadding, defaultStyleValue, + @"iconPadding should return the default value after being unset."); + } + + // icon-rotate + { + XCTAssertTrue(rawLayer->getIconRotate().isUndefined(), + @"icon-rotate should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconRotation; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.iconRotation = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getIconRotate(), propertyValue, + @"Setting iconRotation to a constant value should update icon-rotate."); + XCTAssertEqualObjects(layer.iconRotation, styleValue, + @"iconRotation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconRotation = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconRotate(), propertyValue, + @"Setting iconRotation to a function should update icon-rotate."); + XCTAssertEqualObjects(layer.iconRotation, styleValue, + @"iconRotation should round-trip functions."); + + layer.iconRotation = nil; + XCTAssertTrue(rawLayer->getIconRotate().isUndefined(), + @"Unsetting iconRotation should return icon-rotate to the default value."); + XCTAssertEqualObjects(layer.iconRotation, defaultStyleValue, + @"iconRotation should return the default value after being unset."); + } + + // icon-rotation-alignment + { + XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(), + @"icon-rotation-alignment should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconRotationAlignment; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]]; + layer.iconRotationAlignment = styleValue; + mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto }; + XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue, + @"Setting iconRotationAlignment to a constant value should update icon-rotation-alignment."); + XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue, + @"iconRotationAlignment should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconRotationAlignment = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue, + @"Setting iconRotationAlignment to a function should update icon-rotation-alignment."); + XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue, + @"iconRotationAlignment should round-trip functions."); + + layer.iconRotationAlignment = nil; + XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(), + @"Unsetting iconRotationAlignment should return icon-rotation-alignment to the default value."); + XCTAssertEqualObjects(layer.iconRotationAlignment, defaultStyleValue, + @"iconRotationAlignment should return the default value after being unset."); + } + + // icon-size + { + XCTAssertTrue(rawLayer->getIconSize().isUndefined(), + @"icon-size should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconScale; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.iconScale = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getIconSize(), propertyValue, + @"Setting iconScale to a constant value should update icon-size."); + XCTAssertEqualObjects(layer.iconScale, styleValue, + @"iconScale should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconScale = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconSize(), propertyValue, + @"Setting iconScale to a function should update icon-size."); + XCTAssertEqualObjects(layer.iconScale, styleValue, + @"iconScale should round-trip functions."); + + layer.iconScale = nil; + XCTAssertTrue(rawLayer->getIconSize().isUndefined(), + @"Unsetting iconScale should return icon-size to the default value."); + XCTAssertEqualObjects(layer.iconScale, defaultStyleValue, + @"iconScale should return the default value after being unset."); + } + + // icon-text-fit + { + XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(), + @"icon-text-fit should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFit; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]]; + layer.iconTextFit = styleValue; + mbgl::style::PropertyValue<mbgl::style::IconTextFitType> propertyValue = { mbgl::style::IconTextFitType::Both }; + XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue, + @"Setting iconTextFit to a constant value should update icon-text-fit."); + XCTAssertEqualObjects(layer.iconTextFit, styleValue, + @"iconTextFit should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconTextFit = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::IconTextFitType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue, + @"Setting iconTextFit to a function should update icon-text-fit."); + XCTAssertEqualObjects(layer.iconTextFit, styleValue, + @"iconTextFit should round-trip functions."); + + layer.iconTextFit = nil; + XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(), + @"Unsetting iconTextFit should return icon-text-fit to the default value."); + XCTAssertEqualObjects(layer.iconTextFit, defaultStyleValue, + @"iconTextFit should return the default value after being unset."); + } + + // icon-text-fit-padding + { + XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(), + @"icon-text-fit-padding should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFitPadding; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)] +#else + [NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)] +#endif + ]; + layer.iconTextFitPadding = styleValue; + mbgl::style::PropertyValue<std::array<float, 4>> propertyValue = { { 1, 1, 1, 1 } }; + XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue, + @"Setting iconTextFitPadding to a constant value should update icon-text-fit-padding."); + XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue, + @"iconTextFitPadding should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconTextFitPadding = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 4>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue, + @"Setting iconTextFitPadding to a function should update icon-text-fit-padding."); + XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue, + @"iconTextFitPadding should round-trip functions."); + + layer.iconTextFitPadding = nil; + XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(), + @"Unsetting iconTextFitPadding should return icon-text-fit-padding to the default value."); + XCTAssertEqualObjects(layer.iconTextFitPadding, defaultStyleValue, + @"iconTextFitPadding should return the default value after being unset."); + } + + // icon-keep-upright + { + XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(), + @"icon-keep-upright should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsIconUpright; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.keepsIconUpright = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue, + @"Setting keepsIconUpright to a constant value should update icon-keep-upright."); + XCTAssertEqualObjects(layer.keepsIconUpright, styleValue, + @"keepsIconUpright should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.keepsIconUpright = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue, + @"Setting keepsIconUpright to a function should update icon-keep-upright."); + XCTAssertEqualObjects(layer.keepsIconUpright, styleValue, + @"keepsIconUpright should round-trip functions."); + + layer.keepsIconUpright = nil; + XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(), + @"Unsetting keepsIconUpright should return icon-keep-upright to the default value."); + XCTAssertEqualObjects(layer.keepsIconUpright, defaultStyleValue, + @"keepsIconUpright should return the default value after being unset."); + } + + // text-keep-upright + { + XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(), + @"text-keep-upright should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsTextUpright; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO]; + layer.keepsTextUpright = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { false }; + XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue, + @"Setting keepsTextUpright to a constant value should update text-keep-upright."); + XCTAssertEqualObjects(layer.keepsTextUpright, styleValue, + @"keepsTextUpright should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.keepsTextUpright = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue, + @"Setting keepsTextUpright to a function should update text-keep-upright."); + XCTAssertEqualObjects(layer.keepsTextUpright, styleValue, + @"keepsTextUpright should round-trip functions."); + + layer.keepsTextUpright = nil; + XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(), + @"Unsetting keepsTextUpright should return text-keep-upright to the default value."); + XCTAssertEqualObjects(layer.keepsTextUpright, defaultStyleValue, + @"keepsTextUpright should return the default value after being unset."); + } + + // text-max-angle + { + XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(), + @"text-max-angle should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextAngle; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.maximumTextAngle = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue, + @"Setting maximumTextAngle to a constant value should update text-max-angle."); + XCTAssertEqualObjects(layer.maximumTextAngle, styleValue, + @"maximumTextAngle should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.maximumTextAngle = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue, + @"Setting maximumTextAngle to a function should update text-max-angle."); + XCTAssertEqualObjects(layer.maximumTextAngle, styleValue, + @"maximumTextAngle should round-trip functions."); + + layer.maximumTextAngle = nil; + XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(), + @"Unsetting maximumTextAngle should return text-max-angle to the default value."); + XCTAssertEqualObjects(layer.maximumTextAngle, defaultStyleValue, + @"maximumTextAngle should return the default value after being unset."); + } + + // text-max-width + { + XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(), + @"text-max-width should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextWidth; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.maximumTextWidth = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue, + @"Setting maximumTextWidth to a constant value should update text-max-width."); + XCTAssertEqualObjects(layer.maximumTextWidth, styleValue, + @"maximumTextWidth should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.maximumTextWidth = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue, + @"Setting maximumTextWidth to a function should update text-max-width."); + XCTAssertEqualObjects(layer.maximumTextWidth, styleValue, + @"maximumTextWidth should round-trip functions."); + + layer.maximumTextWidth = nil; + XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(), + @"Unsetting maximumTextWidth should return text-max-width to the default value."); + XCTAssertEqualObjects(layer.maximumTextWidth, defaultStyleValue, + @"maximumTextWidth should return the default value after being unset."); + } + + // symbol-avoid-edges + { + XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(), + @"symbol-avoid-edges should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolAvoidsEdges; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.symbolAvoidsEdges = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue, + @"Setting symbolAvoidsEdges to a constant value should update symbol-avoid-edges."); + XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue, + @"symbolAvoidsEdges should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.symbolAvoidsEdges = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue, + @"Setting symbolAvoidsEdges to a function should update symbol-avoid-edges."); + XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue, + @"symbolAvoidsEdges should round-trip functions."); + + layer.symbolAvoidsEdges = nil; + XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(), + @"Unsetting symbolAvoidsEdges should return symbol-avoid-edges to the default value."); + XCTAssertEqualObjects(layer.symbolAvoidsEdges, defaultStyleValue, + @"symbolAvoidsEdges should return the default value after being unset."); + } + + // symbol-placement + { + XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(), + @"symbol-placement should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.symbolPlacement; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]]; + layer.symbolPlacement = styleValue; + mbgl::style::PropertyValue<mbgl::style::SymbolPlacementType> propertyValue = { mbgl::style::SymbolPlacementType::Line }; + XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue, + @"Setting symbolPlacement to a constant value should update symbol-placement."); + XCTAssertEqualObjects(layer.symbolPlacement, styleValue, + @"symbolPlacement should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.symbolPlacement = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::SymbolPlacementType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue, + @"Setting symbolPlacement to a function should update symbol-placement."); + XCTAssertEqualObjects(layer.symbolPlacement, styleValue, + @"symbolPlacement should round-trip functions."); + + layer.symbolPlacement = nil; + XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(), + @"Unsetting symbolPlacement should return symbol-placement to the default value."); + XCTAssertEqualObjects(layer.symbolPlacement, defaultStyleValue, + @"symbolPlacement should return the default value after being unset."); + } + + // symbol-spacing + { + XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(), + @"symbol-spacing should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolSpacing; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.symbolSpacing = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue, + @"Setting symbolSpacing to a constant value should update symbol-spacing."); + XCTAssertEqualObjects(layer.symbolSpacing, styleValue, + @"symbolSpacing should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.symbolSpacing = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue, + @"Setting symbolSpacing to a function should update symbol-spacing."); + XCTAssertEqualObjects(layer.symbolSpacing, styleValue, + @"symbolSpacing should round-trip functions."); + + layer.symbolSpacing = nil; + XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(), + @"Unsetting symbolSpacing should return symbol-spacing to the default value."); + XCTAssertEqualObjects(layer.symbolSpacing, defaultStyleValue, + @"symbolSpacing should return the default value after being unset."); + } + + // text-field + { + XCTAssertTrue(rawLayer->getTextField().isUndefined(), + @"text-field should be unset initially."); + MGLStyleValue<NSString *> *defaultStyleValue = layer.text; + + MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Text Field"]; + layer.text = styleValue; + mbgl::style::PropertyValue<std::string> propertyValue = { "Text Field" }; + XCTAssertEqual(rawLayer->getTextField(), propertyValue, + @"Setting text to a constant value should update text-field."); + XCTAssertEqualObjects(layer.text, styleValue, + @"text should round-trip constant values."); + + styleValue = [MGLStyleValue<NSString *> valueWithStops:@{ + @18: styleValue, + }]; + layer.text = styleValue; + propertyValue = { mbgl::style::Function<std::string> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextField(), propertyValue, + @"Setting text to a function should update text-field."); + XCTAssertEqualObjects(layer.text, styleValue, + @"text should round-trip functions."); + + layer.text = nil; + XCTAssertTrue(rawLayer->getTextField().isUndefined(), + @"Unsetting text should return text-field to the default value."); + XCTAssertEqualObjects(layer.text, defaultStyleValue, + @"text should return the default value after being unset."); + } + + // text-allow-overlap + { + XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(), + @"text-allow-overlap should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textAllowsOverlap; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.textAllowsOverlap = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue, + @"Setting textAllowsOverlap to a constant value should update text-allow-overlap."); + XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue, + @"textAllowsOverlap should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textAllowsOverlap = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue, + @"Setting textAllowsOverlap to a function should update text-allow-overlap."); + XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue, + @"textAllowsOverlap should round-trip functions."); + + layer.textAllowsOverlap = nil; + XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(), + @"Unsetting textAllowsOverlap should return text-allow-overlap to the default value."); + XCTAssertEqualObjects(layer.textAllowsOverlap, defaultStyleValue, + @"textAllowsOverlap should return the default value after being unset."); + } + + // text-anchor + { + XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(), + @"text-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textAnchor; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]]; + layer.textAnchor = styleValue; + mbgl::style::PropertyValue<mbgl::style::TextAnchorType> propertyValue = { mbgl::style::TextAnchorType::BottomRight }; + XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue, + @"Setting textAnchor to a constant value should update text-anchor."); + XCTAssertEqualObjects(layer.textAnchor, styleValue, + @"textAnchor should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textAnchor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TextAnchorType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue, + @"Setting textAnchor to a function should update text-anchor."); + XCTAssertEqualObjects(layer.textAnchor, styleValue, + @"textAnchor should round-trip functions."); + + layer.textAnchor = nil; + XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(), + @"Unsetting textAnchor should return text-anchor to the default value."); + XCTAssertEqualObjects(layer.textAnchor, defaultStyleValue, + @"textAnchor should return the default value after being unset."); + } + + // text-font + { + XCTAssertTrue(rawLayer->getTextFont().isUndefined(), + @"text-font should be unset initially."); + MGLStyleValue<NSArray<NSString *> *> *defaultStyleValue = layer.textFontNames; + + MGLStyleValue<NSArray<NSString *> *> *styleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]]; + layer.textFontNames = styleValue; + mbgl::style::PropertyValue<std::vector<std::string>> propertyValue = { { "Text Font", "Tnof Txet" } }; + XCTAssertEqual(rawLayer->getTextFont(), propertyValue, + @"Setting textFontNames to a constant value should update text-font."); + XCTAssertEqualObjects(layer.textFontNames, styleValue, + @"textFontNames should round-trip constant values."); + + styleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textFontNames = styleValue; + propertyValue = { mbgl::style::Function<std::vector<std::string>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextFont(), propertyValue, + @"Setting textFontNames to a function should update text-font."); + XCTAssertEqualObjects(layer.textFontNames, styleValue, + @"textFontNames should round-trip functions."); + + layer.textFontNames = nil; + XCTAssertTrue(rawLayer->getTextFont().isUndefined(), + @"Unsetting textFontNames should return text-font to the default value."); + XCTAssertEqualObjects(layer.textFontNames, defaultStyleValue, + @"textFontNames should return the default value after being unset."); + } + + // text-size + { + XCTAssertTrue(rawLayer->getTextSize().isUndefined(), + @"text-size should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textFontSize; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textFontSize = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextSize(), propertyValue, + @"Setting textFontSize to a constant value should update text-size."); + XCTAssertEqualObjects(layer.textFontSize, styleValue, + @"textFontSize should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textFontSize = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextSize(), propertyValue, + @"Setting textFontSize to a function should update text-size."); + XCTAssertEqualObjects(layer.textFontSize, styleValue, + @"textFontSize should round-trip functions."); + + layer.textFontSize = nil; + XCTAssertTrue(rawLayer->getTextSize().isUndefined(), + @"Unsetting textFontSize should return text-size to the default value."); + XCTAssertEqualObjects(layer.textFontSize, defaultStyleValue, + @"textFontSize should return the default value after being unset."); + } + + // text-ignore-placement + { + XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(), + @"text-ignore-placement should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textIgnoresPlacement; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.textIgnoresPlacement = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue, + @"Setting textIgnoresPlacement to a constant value should update text-ignore-placement."); + XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue, + @"textIgnoresPlacement should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textIgnoresPlacement = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue, + @"Setting textIgnoresPlacement to a function should update text-ignore-placement."); + XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue, + @"textIgnoresPlacement should round-trip functions."); + + layer.textIgnoresPlacement = nil; + XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(), + @"Unsetting textIgnoresPlacement should return text-ignore-placement to the default value."); + XCTAssertEqualObjects(layer.textIgnoresPlacement, defaultStyleValue, + @"textIgnoresPlacement should return the default value after being unset."); + } + + // text-justify + { + XCTAssertTrue(rawLayer->getTextJustify().isUndefined(), + @"text-justify should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textJustification; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]]; + layer.textJustification = styleValue; + mbgl::style::PropertyValue<mbgl::style::TextJustifyType> propertyValue = { mbgl::style::TextJustifyType::Right }; + XCTAssertEqual(rawLayer->getTextJustify(), propertyValue, + @"Setting textJustification to a constant value should update text-justify."); + XCTAssertEqualObjects(layer.textJustification, styleValue, + @"textJustification should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textJustification = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TextJustifyType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextJustify(), propertyValue, + @"Setting textJustification to a function should update text-justify."); + XCTAssertEqualObjects(layer.textJustification, styleValue, + @"textJustification should round-trip functions."); + + layer.textJustification = nil; + XCTAssertTrue(rawLayer->getTextJustify().isUndefined(), + @"Unsetting textJustification should return text-justify to the default value."); + XCTAssertEqualObjects(layer.textJustification, defaultStyleValue, + @"textJustification should return the default value after being unset."); + } + + // text-letter-spacing + { + XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(), + @"text-letter-spacing should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLetterSpacing; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textLetterSpacing = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue, + @"Setting textLetterSpacing to a constant value should update text-letter-spacing."); + XCTAssertEqualObjects(layer.textLetterSpacing, styleValue, + @"textLetterSpacing should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textLetterSpacing = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue, + @"Setting textLetterSpacing to a function should update text-letter-spacing."); + XCTAssertEqualObjects(layer.textLetterSpacing, styleValue, + @"textLetterSpacing should round-trip functions."); + + layer.textLetterSpacing = nil; + XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(), + @"Unsetting textLetterSpacing should return text-letter-spacing to the default value."); + XCTAssertEqualObjects(layer.textLetterSpacing, defaultStyleValue, + @"textLetterSpacing should return the default value after being unset."); + } + + // text-line-height + { + XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(), + @"text-line-height should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLineHeight; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textLineHeight = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue, + @"Setting textLineHeight to a constant value should update text-line-height."); + XCTAssertEqualObjects(layer.textLineHeight, styleValue, + @"textLineHeight should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textLineHeight = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue, + @"Setting textLineHeight to a function should update text-line-height."); + XCTAssertEqualObjects(layer.textLineHeight, styleValue, + @"textLineHeight should round-trip functions."); + + layer.textLineHeight = nil; + XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(), + @"Unsetting textLineHeight should return text-line-height to the default value."); + XCTAssertEqualObjects(layer.textLineHeight, defaultStyleValue, + @"textLineHeight should return the default value after being unset."); + } + + // text-offset + { + XCTAssertTrue(rawLayer->getTextOffset().isUndefined(), + @"text-offset should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textOffset; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.textOffset = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getTextOffset(), propertyValue, + @"Setting textOffset to a constant value should update text-offset."); + XCTAssertEqualObjects(layer.textOffset, styleValue, + @"textOffset should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textOffset = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextOffset(), propertyValue, + @"Setting textOffset to a function should update text-offset."); + XCTAssertEqualObjects(layer.textOffset, styleValue, + @"textOffset should round-trip functions."); + + layer.textOffset = nil; + XCTAssertTrue(rawLayer->getTextOffset().isUndefined(), + @"Unsetting textOffset should return text-offset to the default value."); + XCTAssertEqualObjects(layer.textOffset, defaultStyleValue, + @"textOffset should return the default value after being unset."); + } + + // text-optional + { + XCTAssertTrue(rawLayer->getTextOptional().isUndefined(), + @"text-optional should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOptional; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]; + layer.textOptional = styleValue; + mbgl::style::PropertyValue<bool> propertyValue = { true }; + XCTAssertEqual(rawLayer->getTextOptional(), propertyValue, + @"Setting textOptional to a constant value should update text-optional."); + XCTAssertEqualObjects(layer.textOptional, styleValue, + @"textOptional should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textOptional = styleValue; + propertyValue = { mbgl::style::Function<bool> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextOptional(), propertyValue, + @"Setting textOptional to a function should update text-optional."); + XCTAssertEqualObjects(layer.textOptional, styleValue, + @"textOptional should round-trip functions."); + + layer.textOptional = nil; + XCTAssertTrue(rawLayer->getTextOptional().isUndefined(), + @"Unsetting textOptional should return text-optional to the default value."); + XCTAssertEqualObjects(layer.textOptional, defaultStyleValue, + @"textOptional should return the default value after being unset."); + } + + // text-padding + { + XCTAssertTrue(rawLayer->getTextPadding().isUndefined(), + @"text-padding should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textPadding; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textPadding = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextPadding(), propertyValue, + @"Setting textPadding to a constant value should update text-padding."); + XCTAssertEqualObjects(layer.textPadding, styleValue, + @"textPadding should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textPadding = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextPadding(), propertyValue, + @"Setting textPadding to a function should update text-padding."); + XCTAssertEqualObjects(layer.textPadding, styleValue, + @"textPadding should round-trip functions."); + + layer.textPadding = nil; + XCTAssertTrue(rawLayer->getTextPadding().isUndefined(), + @"Unsetting textPadding should return text-padding to the default value."); + XCTAssertEqualObjects(layer.textPadding, defaultStyleValue, + @"textPadding should return the default value after being unset."); + } + + // text-pitch-alignment + { + XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(), + @"text-pitch-alignment should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textPitchAlignment; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]]; + layer.textPitchAlignment = styleValue; + mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto }; + XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue, + @"Setting textPitchAlignment to a constant value should update text-pitch-alignment."); + XCTAssertEqualObjects(layer.textPitchAlignment, styleValue, + @"textPitchAlignment should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textPitchAlignment = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue, + @"Setting textPitchAlignment to a function should update text-pitch-alignment."); + XCTAssertEqualObjects(layer.textPitchAlignment, styleValue, + @"textPitchAlignment should round-trip functions."); + + layer.textPitchAlignment = nil; + XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(), + @"Unsetting textPitchAlignment should return text-pitch-alignment to the default value."); + XCTAssertEqualObjects(layer.textPitchAlignment, defaultStyleValue, + @"textPitchAlignment should return the default value after being unset."); + } + + // text-rotate + { + XCTAssertTrue(rawLayer->getTextRotate().isUndefined(), + @"text-rotate should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textRotation; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textRotation = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextRotate(), propertyValue, + @"Setting textRotation to a constant value should update text-rotate."); + XCTAssertEqualObjects(layer.textRotation, styleValue, + @"textRotation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textRotation = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextRotate(), propertyValue, + @"Setting textRotation to a function should update text-rotate."); + XCTAssertEqualObjects(layer.textRotation, styleValue, + @"textRotation should round-trip functions."); + + layer.textRotation = nil; + XCTAssertTrue(rawLayer->getTextRotate().isUndefined(), + @"Unsetting textRotation should return text-rotate to the default value."); + XCTAssertEqualObjects(layer.textRotation, defaultStyleValue, + @"textRotation should return the default value after being unset."); + } + + // text-rotation-alignment + { + XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(), + @"text-rotation-alignment should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textRotationAlignment; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]]; + layer.textRotationAlignment = styleValue; + mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto }; + XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue, + @"Setting textRotationAlignment to a constant value should update text-rotation-alignment."); + XCTAssertEqualObjects(layer.textRotationAlignment, styleValue, + @"textRotationAlignment should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textRotationAlignment = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue, + @"Setting textRotationAlignment to a function should update text-rotation-alignment."); + XCTAssertEqualObjects(layer.textRotationAlignment, styleValue, + @"textRotationAlignment should round-trip functions."); + + layer.textRotationAlignment = nil; + XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(), + @"Unsetting textRotationAlignment should return text-rotation-alignment to the default value."); + XCTAssertEqualObjects(layer.textRotationAlignment, defaultStyleValue, + @"textRotationAlignment should return the default value after being unset."); + } + + // text-transform + { + XCTAssertTrue(rawLayer->getTextTransform().isUndefined(), + @"text-transform should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTransform; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]]; + layer.textTransform = styleValue; + mbgl::style::PropertyValue<mbgl::style::TextTransformType> propertyValue = { mbgl::style::TextTransformType::Lowercase }; + XCTAssertEqual(rawLayer->getTextTransform(), propertyValue, + @"Setting textTransform to a constant value should update text-transform."); + XCTAssertEqualObjects(layer.textTransform, styleValue, + @"textTransform should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textTransform = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TextTransformType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextTransform(), propertyValue, + @"Setting textTransform to a function should update text-transform."); + XCTAssertEqualObjects(layer.textTransform, styleValue, + @"textTransform should round-trip functions."); + + layer.textTransform = nil; + XCTAssertTrue(rawLayer->getTextTransform().isUndefined(), + @"Unsetting textTransform should return text-transform to the default value."); + XCTAssertEqualObjects(layer.textTransform, defaultStyleValue, + @"textTransform should return the default value after being unset."); + } + + // icon-color + { + XCTAssertTrue(rawLayer->getIconColor().isUndefined(), + @"icon-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.iconColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getIconColor(), propertyValue, + @"Setting iconColor to a constant value should update icon-color."); + XCTAssertEqualObjects(layer.iconColor, styleValue, + @"iconColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconColor(), propertyValue, + @"Setting iconColor to a function should update icon-color."); + XCTAssertEqualObjects(layer.iconColor, styleValue, + @"iconColor should round-trip functions."); + + layer.iconColor = nil; + XCTAssertTrue(rawLayer->getIconColor().isUndefined(), + @"Unsetting iconColor should return icon-color to the default value."); + XCTAssertEqualObjects(layer.iconColor, defaultStyleValue, + @"iconColor should return the default value after being unset."); + } + + // icon-halo-blur + { + XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(), + @"icon-halo-blur should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloBlur; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.iconHaloBlur = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue, + @"Setting iconHaloBlur to a constant value should update icon-halo-blur."); + XCTAssertEqualObjects(layer.iconHaloBlur, styleValue, + @"iconHaloBlur should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconHaloBlur = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue, + @"Setting iconHaloBlur to a function should update icon-halo-blur."); + XCTAssertEqualObjects(layer.iconHaloBlur, styleValue, + @"iconHaloBlur should round-trip functions."); + + layer.iconHaloBlur = nil; + XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(), + @"Unsetting iconHaloBlur should return icon-halo-blur to the default value."); + XCTAssertEqualObjects(layer.iconHaloBlur, defaultStyleValue, + @"iconHaloBlur should return the default value after being unset."); + } + + // icon-halo-color + { + XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(), + @"icon-halo-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconHaloColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.iconHaloColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue, + @"Setting iconHaloColor to a constant value should update icon-halo-color."); + XCTAssertEqualObjects(layer.iconHaloColor, styleValue, + @"iconHaloColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconHaloColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue, + @"Setting iconHaloColor to a function should update icon-halo-color."); + XCTAssertEqualObjects(layer.iconHaloColor, styleValue, + @"iconHaloColor should round-trip functions."); + + layer.iconHaloColor = nil; + XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(), + @"Unsetting iconHaloColor should return icon-halo-color to the default value."); + XCTAssertEqualObjects(layer.iconHaloColor, defaultStyleValue, + @"iconHaloColor should return the default value after being unset."); + } + + // icon-halo-width + { + XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(), + @"icon-halo-width should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloWidth; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.iconHaloWidth = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue, + @"Setting iconHaloWidth to a constant value should update icon-halo-width."); + XCTAssertEqualObjects(layer.iconHaloWidth, styleValue, + @"iconHaloWidth should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconHaloWidth = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue, + @"Setting iconHaloWidth to a function should update icon-halo-width."); + XCTAssertEqualObjects(layer.iconHaloWidth, styleValue, + @"iconHaloWidth should round-trip functions."); + + layer.iconHaloWidth = nil; + XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(), + @"Unsetting iconHaloWidth should return icon-halo-width to the default value."); + XCTAssertEqualObjects(layer.iconHaloWidth, defaultStyleValue, + @"iconHaloWidth should return the default value after being unset."); + } + + // icon-opacity + { + XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(), + @"icon-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.iconOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue, + @"Setting iconOpacity to a constant value should update icon-opacity."); + XCTAssertEqualObjects(layer.iconOpacity, styleValue, + @"iconOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue, + @"Setting iconOpacity to a function should update icon-opacity."); + XCTAssertEqualObjects(layer.iconOpacity, styleValue, + @"iconOpacity should round-trip functions."); + + layer.iconOpacity = nil; + XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(), + @"Unsetting iconOpacity should return icon-opacity to the default value."); + XCTAssertEqualObjects(layer.iconOpacity, defaultStyleValue, + @"iconOpacity should return the default value after being unset."); + } + + // icon-translate + { + XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(), + @"icon-translate should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslation; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.iconTranslation = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue, + @"Setting iconTranslation to a constant value should update icon-translate."); + XCTAssertEqualObjects(layer.iconTranslation, styleValue, + @"iconTranslation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconTranslation = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue, + @"Setting iconTranslation to a function should update icon-translate."); + XCTAssertEqualObjects(layer.iconTranslation, styleValue, + @"iconTranslation should round-trip functions."); + + layer.iconTranslation = nil; + XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(), + @"Unsetting iconTranslation should return icon-translate to the default value."); + XCTAssertEqualObjects(layer.iconTranslation, defaultStyleValue, + @"iconTranslation should return the default value after being unset."); + } + + // icon-translate-anchor + { + XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(), + @"icon-translate-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslationAnchor; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]]; + layer.iconTranslationAnchor = styleValue; + mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; + XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue, + @"Setting iconTranslationAnchor to a constant value should update icon-translate-anchor."); + XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue, + @"iconTranslationAnchor should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.iconTranslationAnchor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue, + @"Setting iconTranslationAnchor to a function should update icon-translate-anchor."); + XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue, + @"iconTranslationAnchor should round-trip functions."); + + layer.iconTranslationAnchor = nil; + XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(), + @"Unsetting iconTranslationAnchor should return icon-translate-anchor to the default value."); + XCTAssertEqualObjects(layer.iconTranslationAnchor, defaultStyleValue, + @"iconTranslationAnchor should return the default value after being unset."); + } + + // text-color + { + XCTAssertTrue(rawLayer->getTextColor().isUndefined(), + @"text-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.textColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getTextColor(), propertyValue, + @"Setting textColor to a constant value should update text-color."); + XCTAssertEqualObjects(layer.textColor, styleValue, + @"textColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextColor(), propertyValue, + @"Setting textColor to a function should update text-color."); + XCTAssertEqualObjects(layer.textColor, styleValue, + @"textColor should round-trip functions."); + + layer.textColor = nil; + XCTAssertTrue(rawLayer->getTextColor().isUndefined(), + @"Unsetting textColor should return text-color to the default value."); + XCTAssertEqualObjects(layer.textColor, defaultStyleValue, + @"textColor should return the default value after being unset."); + } + + // text-halo-blur + { + XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(), + @"text-halo-blur should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloBlur; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textHaloBlur = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue, + @"Setting textHaloBlur to a constant value should update text-halo-blur."); + XCTAssertEqualObjects(layer.textHaloBlur, styleValue, + @"textHaloBlur should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textHaloBlur = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue, + @"Setting textHaloBlur to a function should update text-halo-blur."); + XCTAssertEqualObjects(layer.textHaloBlur, styleValue, + @"textHaloBlur should round-trip functions."); + + layer.textHaloBlur = nil; + XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(), + @"Unsetting textHaloBlur should return text-halo-blur to the default value."); + XCTAssertEqualObjects(layer.textHaloBlur, defaultStyleValue, + @"textHaloBlur should return the default value after being unset."); + } + + // text-halo-color + { + XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(), + @"text-halo-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textHaloColor; + + MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.textHaloColor = styleValue; + mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue, + @"Setting textHaloColor to a constant value should update text-halo-color."); + XCTAssertEqualObjects(layer.textHaloColor, styleValue, + @"textHaloColor should round-trip constant values."); + + styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textHaloColor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::Color> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue, + @"Setting textHaloColor to a function should update text-halo-color."); + XCTAssertEqualObjects(layer.textHaloColor, styleValue, + @"textHaloColor should round-trip functions."); + + layer.textHaloColor = nil; + XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(), + @"Unsetting textHaloColor should return text-halo-color to the default value."); + XCTAssertEqualObjects(layer.textHaloColor, defaultStyleValue, + @"textHaloColor should return the default value after being unset."); + } + + // text-halo-width + { + XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(), + @"text-halo-width should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloWidth; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textHaloWidth = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue, + @"Setting textHaloWidth to a constant value should update text-halo-width."); + XCTAssertEqualObjects(layer.textHaloWidth, styleValue, + @"textHaloWidth should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textHaloWidth = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue, + @"Setting textHaloWidth to a function should update text-halo-width."); + XCTAssertEqualObjects(layer.textHaloWidth, styleValue, + @"textHaloWidth should round-trip functions."); + + layer.textHaloWidth = nil; + XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(), + @"Unsetting textHaloWidth should return text-halo-width to the default value."); + XCTAssertEqualObjects(layer.textHaloWidth, defaultStyleValue, + @"textHaloWidth should return the default value after being unset."); + } + + // text-opacity + { + XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(), + @"text-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOpacity; + + MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.textOpacity = styleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue, + @"Setting textOpacity to a constant value should update text-opacity."); + XCTAssertEqualObjects(layer.textOpacity, styleValue, + @"textOpacity should round-trip constant values."); + + styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textOpacity = styleValue; + propertyValue = { mbgl::style::Function<float> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue, + @"Setting textOpacity to a function should update text-opacity."); + XCTAssertEqualObjects(layer.textOpacity, styleValue, + @"textOpacity should round-trip functions."); + + layer.textOpacity = nil; + XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(), + @"Unsetting textOpacity should return text-opacity to the default value."); + XCTAssertEqualObjects(layer.textOpacity, defaultStyleValue, + @"textOpacity should return the default value after being unset."); + } + + // text-translate + { + XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(), + @"text-translate should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslation; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.textTranslation = styleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue, + @"Setting textTranslation to a constant value should update text-translate."); + XCTAssertEqualObjects(layer.textTranslation, styleValue, + @"textTranslation should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textTranslation = styleValue; + propertyValue = { mbgl::style::Function<std::array<float, 2>> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue, + @"Setting textTranslation to a function should update text-translate."); + XCTAssertEqualObjects(layer.textTranslation, styleValue, + @"textTranslation should round-trip functions."); + + layer.textTranslation = nil; + XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(), + @"Unsetting textTranslation should return text-translate to the default value."); + XCTAssertEqualObjects(layer.textTranslation, defaultStyleValue, + @"textTranslation should return the default value after being unset."); + } + + // text-translate-anchor + { + XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(), + @"text-translate-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslationAnchor; + + MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]]; + layer.textTranslationAnchor = styleValue; + mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; + XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue, + @"Setting textTranslationAnchor to a constant value should update text-translate-anchor."); + XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue, + @"textTranslationAnchor should round-trip constant values."); + + styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{ + @18: styleValue, + }]; + layer.textTranslationAnchor = styleValue; + propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> { + {{ 18, propertyValue.asConstant() }}, + 1, + }}; + XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue, + @"Setting textTranslationAnchor to a function should update text-translate-anchor."); + XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue, + @"textTranslationAnchor should round-trip functions."); + + layer.textTranslationAnchor = nil; + XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(), + @"Unsetting textTranslationAnchor should return text-translate-anchor to the default value."); + XCTAssertEqualObjects(layer.textTranslationAnchor, defaultStyleValue, + @"textTranslationAnchor should return the default value after being unset."); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"icon-allows-overlap" isBoolean:YES]; + [self testPropertyName:@"icon-ignores-placement" isBoolean:YES]; + [self testPropertyName:@"icon-image-name" isBoolean:NO]; + [self testPropertyName:@"icon-offset" isBoolean:NO]; + [self testPropertyName:@"is-icon-optional" isBoolean:YES]; + [self testPropertyName:@"icon-padding" isBoolean:NO]; + [self testPropertyName:@"icon-rotation" isBoolean:NO]; + [self testPropertyName:@"icon-rotation-alignment" isBoolean:NO]; + [self testPropertyName:@"icon-scale" isBoolean:NO]; + [self testPropertyName:@"icon-text-fit" isBoolean:NO]; + [self testPropertyName:@"icon-text-fit-padding" isBoolean:NO]; + [self testPropertyName:@"keeps-icon-upright" isBoolean:YES]; + [self testPropertyName:@"keeps-text-upright" isBoolean:YES]; + [self testPropertyName:@"maximum-text-angle" isBoolean:NO]; + [self testPropertyName:@"maximum-text-width" isBoolean:NO]; + [self testPropertyName:@"symbol-avoids-edges" isBoolean:YES]; + [self testPropertyName:@"symbol-placement" isBoolean:NO]; + [self testPropertyName:@"symbol-spacing" isBoolean:NO]; + [self testPropertyName:@"text" isBoolean:NO]; + [self testPropertyName:@"text-allows-overlap" isBoolean:YES]; + [self testPropertyName:@"text-anchor" isBoolean:NO]; + [self testPropertyName:@"text-font-names" isBoolean:NO]; + [self testPropertyName:@"text-font-size" isBoolean:NO]; + [self testPropertyName:@"text-ignores-placement" isBoolean:YES]; + [self testPropertyName:@"text-justification" isBoolean:NO]; + [self testPropertyName:@"text-letter-spacing" isBoolean:NO]; + [self testPropertyName:@"text-line-height" isBoolean:NO]; + [self testPropertyName:@"text-offset" isBoolean:NO]; + [self testPropertyName:@"is-text-optional" isBoolean:YES]; + [self testPropertyName:@"text-padding" isBoolean:NO]; + [self testPropertyName:@"text-pitch-alignment" isBoolean:NO]; + [self testPropertyName:@"text-rotation" isBoolean:NO]; + [self testPropertyName:@"text-rotation-alignment" isBoolean:NO]; + [self testPropertyName:@"text-transform" isBoolean:NO]; + [self testPropertyName:@"icon-color" isBoolean:NO]; + [self testPropertyName:@"icon-halo-blur" isBoolean:NO]; + [self testPropertyName:@"icon-halo-color" isBoolean:NO]; + [self testPropertyName:@"icon-halo-width" isBoolean:NO]; + [self testPropertyName:@"icon-opacity" isBoolean:NO]; + [self testPropertyName:@"icon-translation" isBoolean:NO]; + [self testPropertyName:@"icon-translation-anchor" isBoolean:NO]; + [self testPropertyName:@"text-color" isBoolean:NO]; + [self testPropertyName:@"text-halo-blur" isBoolean:NO]; + [self testPropertyName:@"text-halo-color" isBoolean:NO]; + [self testPropertyName:@"text-halo-width" isBoolean:NO]; + [self testPropertyName:@"text-opacity" isBoolean:NO]; + [self testPropertyName:@"text-translation" isBoolean:NO]; + [self testPropertyName:@"text-translation-anchor" isBoolean:NO]; +} + +- (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentMap].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentMap); + XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentViewport].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentViewport); + XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentAuto); + XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitNone].MGLIconTextFitValue, MGLIconTextFitNone); + XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitWidth].MGLIconTextFitValue, MGLIconTextFitWidth); + XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitHeight].MGLIconTextFitValue, MGLIconTextFitHeight); + XCTAssertEqual([NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth].MGLIconTextFitValue, MGLIconTextFitBoth); + XCTAssertEqual([NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementPoint].MGLSymbolPlacementValue, MGLSymbolPlacementPoint); + XCTAssertEqual([NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine].MGLSymbolPlacementValue, MGLSymbolPlacementLine); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorCenter].MGLTextAnchorValue, MGLTextAnchorCenter); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorLeft].MGLTextAnchorValue, MGLTextAnchorLeft); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorRight].MGLTextAnchorValue, MGLTextAnchorRight); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTop].MGLTextAnchorValue, MGLTextAnchorTop); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottom].MGLTextAnchorValue, MGLTextAnchorBottom); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTopLeft].MGLTextAnchorValue, MGLTextAnchorTopLeft); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTopRight].MGLTextAnchorValue, MGLTextAnchorTopRight); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomLeft].MGLTextAnchorValue, MGLTextAnchorBottomLeft); + XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight].MGLTextAnchorValue, MGLTextAnchorBottomRight); + XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationLeft].MGLTextJustificationValue, MGLTextJustificationLeft); + XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationCenter].MGLTextJustificationValue, MGLTextJustificationCenter); + XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationRight].MGLTextJustificationValue, MGLTextJustificationRight); + XCTAssertEqual([NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentMap].MGLTextPitchAlignmentValue, MGLTextPitchAlignmentMap); + XCTAssertEqual([NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentViewport].MGLTextPitchAlignmentValue, MGLTextPitchAlignmentViewport); + XCTAssertEqual([NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto].MGLTextPitchAlignmentValue, MGLTextPitchAlignmentAuto); + XCTAssertEqual([NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentMap].MGLTextRotationAlignmentValue, MGLTextRotationAlignmentMap); + XCTAssertEqual([NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentViewport].MGLTextRotationAlignmentValue, MGLTextRotationAlignmentViewport); + XCTAssertEqual([NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto].MGLTextRotationAlignmentValue, MGLTextRotationAlignmentAuto); + XCTAssertEqual([NSValue valueWithMGLTextTransform:MGLTextTransformNone].MGLTextTransformValue, MGLTextTransformNone); + XCTAssertEqual([NSValue valueWithMGLTextTransform:MGLTextTransformUppercase].MGLTextTransformValue, MGLTextTransformUppercase); + XCTAssertEqual([NSValue valueWithMGLTextTransform:MGLTextTransformLowercase].MGLTextTransformValue, MGLTextTransformLowercase); + XCTAssertEqual([NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorMap].MGLIconTranslationAnchorValue, MGLIconTranslationAnchorMap); + XCTAssertEqual([NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport].MGLIconTranslationAnchorValue, MGLIconTranslationAnchorViewport); + XCTAssertEqual([NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorMap].MGLTextTranslationAnchorValue, MGLTextTranslationAnchorMap); + XCTAssertEqual([NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport].MGLTextTranslationAnchorValue, MGLTextTranslationAnchorViewport); +} + +@end diff --git a/platform/darwin/test/one-liner.json b/platform/darwin/test/one-liner.json new file mode 100644 index 0000000000..23c546181f --- /dev/null +++ b/platform/darwin/test/one-liner.json @@ -0,0 +1 @@ +{"version":8,"sources":{},"layers":[]}
\ No newline at end of file |