From cb1ed935646283e823ec62d5d4978907416f95e1 Mon Sep 17 00:00:00 2001 From: Ivan Persidsky Date: Wed, 17 Jul 2024 19:07:45 +0300 Subject: [PATCH] Generic annotations implementation --- .swiftlint.yml | 1 + .../MapboxMaps/Annotations/Annotation.swift | 18 + .../AnnotationManagerFactory.swift | 99 - .../Annotations/AnnotationManagerImpl.swift | 473 +++ .../Annotations/AnnotationManagerTraits.swift | 64 + .../Annotations/AnnotationOrchestrator.swift | 94 +- .../AnnotationOrchestratorImpl.swift | 137 - .../Generated/CircleAnnotation.swift | 13 +- .../Generated/CircleAnnotationManager.swift | 402 +-- .../Generated/PointAnnotation.swift | 13 +- .../Generated/PointAnnotationManager.swift | 770 +--- .../Generated/PolygonAnnotation.swift | 13 +- .../Generated/PolygonAnnotationManager.swift | 394 +-- .../Generated/PolylineAnnotation.swift | 13 +- .../Generated/PolylineAnnotationManager.swift | 462 +-- .../OffsetGeometryCalculator.swift | 3 +- .../MapContent/MapContentAnnotation.swift | 20 - .../MapContent/MountedAnnotationGroup.swift | 36 +- Sources/MapboxMaps/Foundation/MapView.swift | 14 +- .../MapViewDependencyProvider.swift | 33 +- .../Gestures/MapContentGestureManager.swift | 16 +- .../Generated/CircleAnnotationGroup.swift | 12 - .../Generated/PointAnnotationGroup.swift | 12 - .../Generated/PolygonAnnotationGroup.swift | 12 - .../Generated/PolylineAnnotationGroup.swift | 12 - .../AnnotationManagerFactoryTests.swift | 93 - .../AnnotationManagerImplTests.swift | 741 ++++ .../AnnotationManagerTestingHarness.swift | 28 + .../AnnotationOrchestratorImplTests.swift | 195 - .../AnotationOrchestratorTests.swift | 85 - .../CircleAnnotationIntegrationTests.swift | 58 +- .../CircleAnnotationManagerTests.swift | 752 +--- .../PointAnnotationIntegrationTests.swift | 266 +- .../PointAnnotationManagerTests.swift | 3144 +---------------- .../PolygonAnnotationIntegrationTests.swift | 42 +- .../PolygonAnnotationManagerTests.swift | 822 +---- .../PolylineAnnotationIntegrationTests.swift | 102 +- .../PolylineAnnotationManagerTests.swift | 1214 +------ .../Mocks/MockAnnotationManager.swift | 8 +- .../Mocks/MockAnnotationManagerFactory.swift | 59 - .../Mocks/MockAnnotationOrchestatorImpl.swift | 97 - .../Mocks/MockMapViewDependencyProvider.swift | 24 +- .../MapContentGestureManagerTests.swift | 17 +- .../DSL/MapStyleContentReconcilerTests.swift | 105 +- 44 files changed, 2262 insertions(+), 8726 deletions(-) delete mode 100644 Sources/MapboxMaps/Annotations/AnnotationManagerFactory.swift create mode 100644 Sources/MapboxMaps/Annotations/AnnotationManagerImpl.swift create mode 100644 Sources/MapboxMaps/Annotations/AnnotationManagerTraits.swift delete mode 100644 Sources/MapboxMaps/Annotations/AnnotationOrchestratorImpl.swift delete mode 100644 Sources/MapboxMaps/ContentBuilders/MapContent/MapContentAnnotation.swift delete mode 100644 Tests/MapboxMapsTests/Annotations/AnnotationManagerFactoryTests.swift create mode 100644 Tests/MapboxMapsTests/Annotations/AnnotationManagerImplTests.swift create mode 100644 Tests/MapboxMapsTests/Annotations/AnnotationManagerTestingHarness.swift delete mode 100644 Tests/MapboxMapsTests/Annotations/AnnotationOrchestratorImplTests.swift delete mode 100644 Tests/MapboxMapsTests/Annotations/AnotationOrchestratorTests.swift delete mode 100644 Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManagerFactory.swift delete mode 100644 Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationOrchestatorImpl.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 628a64b6e57f..f5ee866dcf81 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -15,6 +15,7 @@ disabled_rules: - todo - trailing_comma - type_name + - type_body_length custom_rules: trojan_source: regex: "[\u202A\u202B\u202D\u202E\u2066\u2067\u2068\u202C\u2069]" diff --git a/Sources/MapboxMaps/Annotations/Annotation.swift b/Sources/MapboxMaps/Annotations/Annotation.swift index 314c07885642..ff8c5ae77470 100644 --- a/Sources/MapboxMaps/Annotations/Annotation.swift +++ b/Sources/MapboxMaps/Annotations/Annotation.swift @@ -12,6 +12,24 @@ public protocol Annotation { var userInfo: [String: Any]? { get set } } +protocol AnnotationInternal { + associatedtype GeometryType: GeometryConvertible + + var id: String { get set } + var layerProperties: [String: Any] { get } + var feature: Feature { get } + var isSelected: Bool { get set } + var isDraggable: Bool { get set } + var _geometry: GeometryType { get set } + + var tapHandler: ((MapContentGestureContext) -> Bool)? { get set } + var longPressHandler: ((MapContentGestureContext) -> Bool)? { get set } + + var dragBeginHandler: ((inout Self, MapContentGestureContext) -> Bool)? { get set } + var dragChangeHandler: ((inout Self, MapContentGestureContext) -> Void)? { get set } + var dragEndHandler: ((inout Self, MapContentGestureContext) -> Void)? { get set } +} + extension Array where Element: Annotation { /// Deduplicates annotations. mutating func removeDuplicates() { diff --git a/Sources/MapboxMaps/Annotations/AnnotationManagerFactory.swift b/Sources/MapboxMaps/Annotations/AnnotationManagerFactory.swift deleted file mode 100644 index c8e5ecd883a8..000000000000 --- a/Sources/MapboxMaps/Annotations/AnnotationManagerFactory.swift +++ /dev/null @@ -1,99 +0,0 @@ -import UIKit - -internal protocol AnnotationManagerFactoryProtocol: AnyObject { - func makePointAnnotationManager( - id: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions? - ) -> AnnotationManagerInternal - - func makePolygonAnnotationManager( - id: String, - layerPosition: LayerPosition? - ) -> AnnotationManagerInternal - - func makePolylineAnnotationManager( - id: String, - layerPosition: LayerPosition? - ) -> AnnotationManagerInternal - - func makeCircleAnnotationManager( - id: String, - layerPosition: LayerPosition? - ) -> AnnotationManagerInternal -} - -internal final class AnnotationManagerFactory: AnnotationManagerFactoryProtocol { - private var displayLink: Signal - private let style: StyleProtocol - private let offsetPointCalculator: OffsetPointCalculator - private let offsetPolygonCalculator: OffsetPolygonCalculator - private let offsetLineStringCalculator: OffsetLineStringCalculator - private let mapFeatureQueryable: MapFeatureQueryable - - private lazy var imagesManager = AnnotationImagesManager(style: style) - - internal init( - style: StyleProtocol, - displayLink: Signal, - offsetPointCalculator: OffsetPointCalculator, - offsetPolygonCalculator: OffsetPolygonCalculator, - offsetLineStringCalculator: OffsetLineStringCalculator, - mapFeatureQueryable: MapFeatureQueryable - ) { - self.style = style - self.displayLink = displayLink - self.offsetPointCalculator = offsetPointCalculator - self.offsetPolygonCalculator = offsetPolygonCalculator - self.offsetLineStringCalculator = offsetLineStringCalculator - self.mapFeatureQueryable = mapFeatureQueryable - } - - internal func makePointAnnotationManager( - id: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions?) -> AnnotationManagerInternal { - return PointAnnotationManager( - id: id, - style: style, - layerPosition: layerPosition, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetPointCalculator) - } - - internal func makePolygonAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return PolygonAnnotationManager( - id: id, - style: style, - layerPosition: layerPosition, - displayLink: displayLink, - offsetCalculator: offsetPolygonCalculator) - } - - internal func makePolylineAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return PolylineAnnotationManager( - id: id, - style: style, - layerPosition: layerPosition, - displayLink: displayLink, - offsetCalculator: offsetLineStringCalculator) - } - - internal func makeCircleAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return CircleAnnotationManager( - id: id, - style: style, - layerPosition: layerPosition, - displayLink: displayLink, - offsetCalculator: offsetPointCalculator) - } -} diff --git a/Sources/MapboxMaps/Annotations/AnnotationManagerImpl.swift b/Sources/MapboxMaps/Annotations/AnnotationManagerImpl.swift new file mode 100644 index 000000000000..59c8ad210fe2 --- /dev/null +++ b/Sources/MapboxMaps/Annotations/AnnotationManagerImpl.swift @@ -0,0 +1,473 @@ +import os + +protocol AnnotationManagerImplDelegate: AnyObject { + func didTap(_ annotations: [Annotation]) + func syncImages() + func removeAllImages() +} + +protocol AnnotationManagerImplProtocol { + var allLayerIds: [String] { get } + + func destroy() + + func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool + func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool + func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool + func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) + func handleDragEnd(context: MapContentGestureContext) +} + +final class AnnotationManagerImpl: AnnotationManagerImplProtocol { + typealias AnnotationType = Traits.AnnotationType + + let id: String + + weak var delegate: AnnotationManagerImplDelegate? + + var annotations: [Traits.AnnotationType] { + get { mainAnnotations + draggedAnnotations } + set { + mainAnnotations = newValue + mainAnnotations.removeDuplicates() + draggedAnnotations.removeAll(keepingCapacity: true) + draggedAnnotationIndex = nil + } + } + + var onClusterTap: ((AnnotationClusterGestureContext) -> Void)? + var onClusterLongPress: ((AnnotationClusterGestureContext) -> Void)? + + // Deps + private let style: StyleProtocol + private let offsetCalculator: Traits.OffsetCalculator + private let mapFeatureQueryable: MapFeatureQueryable + private let clusterOptions: ClusterOptions? + private let layerType: LayerType + + private var dragId: String { "\(id)_drag" } + private var clusterId: String? + var allLayerIds: [String] { [id, dragId, clusterId].compactMap { $0 } } + + // Private state + + private weak var _delegate: AnnotationInteractionDelegate? + + /// Currently displayed (synced) annotations. + private var displayedAnnotations: [Traits.AnnotationType] = [] + + /// Updated, non-moved annotations. On next display link they will be diffed with `displayedAnnotations` and updated. + private var mainAnnotations = [Traits.AnnotationType]() { + didSet { syncSourceOnce.reset() } + } + + /// When annotation is moved for the first time, it migrates to this array from mainAnnotations. + private var draggedAnnotations = [Traits.AnnotationType]() { + didSet { + if insertDraggedLayerAndSourceOnce.happened { + // Update dragged annotation only when the drag layer is created. + syncDragSourceOnce.reset() + } + } + } + + private var idsMap = [AnyHashable: String]() + + /// Storage for common layer properties + var layerProperties: [String: Any] = [:] { + didSet { + syncLayerOnce.reset() + } + } + + /// The keys of the style properties that were set during the previous sync. + /// Used to identify which styles need to be restored to their default values in + /// the subsequent sync. + private var previouslySetLayerPropertyKeys: Set = [] + + private var draggedAnnotationIndex: Array.Index? + private var destroyOnce = Once() + private var syncSourceOnce = Once(happened: true) + private var syncDragSourceOnce = Once(happened: true) + private var syncLayerOnce = Once(happened: true) + private var insertDraggedLayerAndSourceOnce = Once() + private var displayLinkToken: AnyCancelable? + + /// In SwiftUI isDraggable and isSelected are disabled. + var isSwiftUI = false + + var layerPosition: LayerPosition? { + didSet { + do { + try style.moveLayer(withId: id, to: layerPosition ?? .default) + } catch { + Log.error(forMessage: "Failed to mover layer to a new position. Error: \(error)", category: "Annotations") + } + } + } + + init(params: AnnotationManagerParams, deps: AnnotationManagerDeps) { + self.id = params.id + self.style = deps.style + self.offsetCalculator = deps.makeOffsetCalculator() + self.layerPosition = params.layerPosition + + self.clusterOptions = params.clusterOptions + self.mapFeatureQueryable = deps.queryable + + // Add the source with empty `data` property + var source = GeoJSONSource(id: id) + + // Set cluster options and create clusters if clustering is enabled + if let clusterOptions { + source.cluster = true + source.clusterRadius = clusterOptions.clusterRadius + source.clusterProperties = clusterOptions.clusterProperties + source.clusterMaxZoom = clusterOptions.clusterMaxZoom + source.clusterMinPoints = clusterOptions.clusterMinPoints + } + + let layer = Traits.makeLayer(id: id) + self.layerType = layer.type + + if let clusterOptions { + clusterId = "mapbox-iOS-cluster-circle-layer-manager-\(id)" + createClusterLayers(clusterOptions: clusterOptions) + } + + do { + try style.addPersistentLayer(layer, layerPosition: layerPosition) + try style.addSource(source) + } catch { + Log.error( + forMessage: "Failed to create source / layer in \(Traits.tag). Error: \(error)", + category: "Annotations") + } + + displayLinkToken = deps.displayLink.observe { [weak self] in + self?.syncSourceAndLayerIfNeeded() + } + } + + private func createClusterLayers(clusterOptions: ClusterOptions) { + let clusterLevelLayer = createClusterLevelLayer(clusterOptions: clusterOptions) + let clusterTextLayer = createClusterTextLayer(clusterOptions: clusterOptions) + do { + try addClusterLayer(clusterLayer: clusterLevelLayer) + try addClusterLayer(clusterLayer: clusterTextLayer) + } catch { + Log.error( + forMessage: "Failed to add cluster layer in \(Traits.tag). Error: \(error)", + category: "Annotations") + } + } + + private func addClusterLayer(clusterLayer: Layer) throws { + guard style.layerExists(withId: clusterLayer.id) else { + try style.addPersistentLayer(clusterLayer, layerPosition: .default) + return + } + } + + private func createClusterLevelLayer(clusterOptions: ClusterOptions) -> CircleLayer { + let layedID = "mapbox-iOS-cluster-circle-layer-manager-" + id + var circleLayer = CircleLayer(id: layedID, source: id) + circleLayer.circleColor = clusterOptions.circleColor + circleLayer.circleRadius = clusterOptions.circleRadius + circleLayer.filter = Exp(.has) { "point_count" } + return circleLayer + } + + private func createClusterTextLayer(clusterOptions: ClusterOptions) -> SymbolLayer { + let layerID = "mapbox-iOS-cluster-text-layer-manager-" + id + var symbolLayer = SymbolLayer(id: layerID, source: id) + symbolLayer.textField = clusterOptions.textField + symbolLayer.textSize = clusterOptions.textSize + symbolLayer.textColor = clusterOptions.textColor + return symbolLayer + } + + private func destroyClusterLayers() { + do { + try style.removeLayer(withId: "mapbox-iOS-cluster-circle-layer-manager-" + id) + try style.removeLayer(withId: "mapbox-iOS-cluster-text-layer-manager-" + id) + } catch { + Log.error( + forMessage: "Failed to remove cluster layer in \(Traits.tag). Error: \(error)", + category: "Annotations") + } + } + + // For SwiftUI + func set(newAnnotations: [(AnyHashable, Traits.AnnotationType)]) { + var resolvedAnnotations = [Traits.AnnotationType]() + newAnnotations.forEach { elementId, annotation in + var annotation = annotation + let stringId = idsMap[elementId] ?? annotation.id + idsMap[elementId] = stringId + annotation.id = stringId + annotation.isDraggable = false + annotation.isSelected = false + resolvedAnnotations.append(annotation) + } + // TODO: evict old ids + annotations = resolvedAnnotations + } + + func destroy() { + guard destroyOnce.continueOnce() else { return } + + displayLinkToken?.cancel() + + if clusterOptions != nil { + destroyClusterLayers() + } + + func wrapError(_ what: String, _ body: () throws -> Void) { + do { + try body() + } catch { + Log.warning( + forMessage: "Failed to remove \(what) for PointAnnotationManager with id \(id) due to error: \(error)", + category: "Annotations") + } + } + + wrapError("layer") { + try style.removeLayer(withId: id) + } + + wrapError("source") { + try style.removeSource(withId: id) + } + + if insertDraggedLayerAndSourceOnce.happened { + wrapError("drag source and layer") { + try style.removeLayer(withId: dragId) + try style.removeSource(withId: dragId) + } + } + + delegate?.removeAllImages() + } + + // MARK: - Sync annotations to map + + // internal for tests + func syncSourceAndLayerIfNeeded() { + guard !destroyOnce.happened else { return } + + OSLog.platform.withIntervalSignpost(SignpostName.mapViewDisplayLink, "Participant: \(Traits.tag)") { + syncSource() + syncDragSource() + syncLayer() + } + } + + private func syncSource() { + guard syncSourceOnce.continueOnce() else { return } + + let diff = mainAnnotations.diff(from: displayedAnnotations, id: \.id) + syncLayerOnce.reset(if: !diff.isEmpty) + style.apply(annotationsDiff: diff, sourceId: id, feature: \.feature) + displayedAnnotations = mainAnnotations + } + + private func syncDragSource() { + guard syncDragSourceOnce.continueOnce() else { return } + + let fc = FeatureCollection(features: draggedAnnotations.map(\.feature)) + style.updateGeoJSONSource(withId: dragId, geoJSON: .featureCollection(fc)) + } + + private func syncLayer() { + guard syncLayerOnce.continueOnce() else { return } + + delegate?.syncImages() + + // Construct the properties dictionary from the annotations + let dataDrivenLayerPropertyKeys = Set(annotations.flatMap(\.layerProperties.keys)) + let dataDrivenProperties = Dictionary( + uniqueKeysWithValues: dataDrivenLayerPropertyKeys + .map { (key) -> (String, Any) in + (key, ["get", key, ["get", "layerProperties"]] as [Any]) + }) + + // Merge the common layer properties + let newLayerProperties = dataDrivenProperties.merging(layerProperties, uniquingKeysWith: { $1 }) + + // Construct the properties dictionary to reset any properties that are no longer used + let unusedPropertyKeys = previouslySetLayerPropertyKeys.subtracting(newLayerProperties.keys) + let unusedProperties = Dictionary(uniqueKeysWithValues: unusedPropertyKeys.map { (key) -> (String, Any) in + (key, StyleManager.layerPropertyDefaultValue(for: self.layerType, property: key).value) + }) + + // Store the new set of property keys + previouslySetLayerPropertyKeys = Set(newLayerProperties.keys) + + // Merge the new and unused properties + let allLayerProperties = newLayerProperties.merging(unusedProperties, uniquingKeysWith: { $1 }) + + // make a single call into MapboxCoreMaps to set layer properties + do { + try style.setLayerProperties(for: id, properties: allLayerProperties) + if !draggedAnnotations.isEmpty { + try style.setLayerProperties(for: dragId, properties: allLayerProperties) + } + } catch { + Log.error( + forMessage: "Could not set layer properties in PointAnnotationManager due to error \(error)", + category: "Annotations") + } + } + + // MARK: - User interaction handling + + private var queryToken: AnyCancelable? + private func queryAnnotationClusterContext( + feature: Feature, + context: MapContentGestureContext, + completion: @escaping (Result) -> Void + ) { + queryToken = mapFeatureQueryable + .getAnnotationClusterContext(layerId: id, feature: feature, context: context, completion: completion) + .erased + } + + func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { + if layerId == clusterId, let onClusterTap { + queryAnnotationClusterContext(feature: feature, context: context) { result in + if case let .success(clusterContext) = result { + onClusterTap(clusterContext) + } + } + return true + } + + guard let featureId = feature.identifier?.string else { return false } + + let tappedIndex = annotations.firstIndex { $0.id == featureId } + guard let tappedIndex else { return false } + var tappedAnnotation = annotations[tappedIndex] + + tappedAnnotation.isSelected.toggle() + + if !isSwiftUI { + // In-place update of annotations is not supported in SwiftUI. + // Use the .onTapGesture {} to update annotations on call side. + self.annotations[tappedIndex] = tappedAnnotation + } + + delegate?.didTap([tappedAnnotation]) + + return tappedAnnotation.tapHandler?(context) ?? false + } + + func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { + if layerId == clusterId, let onClusterLongPress { + queryAnnotationClusterContext(feature: feature, context: context) { result in + if case let .success(clusterContext) = result { + onClusterLongPress(clusterContext) + } + } + return true + } + guard let featureId = feature.identifier?.string else { return false } + + return annotations.first { $0.id == featureId }?.longPressHandler?(context) ?? false + } + + func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool { + guard !isSwiftUI else { return false } + + func predicate(annotation: Traits.AnnotationType) -> Bool { + annotation.id == featureId && annotation.isDraggable + } + + func tryBeginDragging(_ annotations: inout [Traits.AnnotationType], idx: Int) -> Bool { + var annotation = annotations[idx] + // If no drag handler set, the dragging is allowed + let dragAllowed = annotation.dragBeginHandler?(&annotation, context) ?? true + annotations[idx] = annotation + return dragAllowed + } + + /// First, try to drag annotations that are already on the dragging layer. + if let idx = draggedAnnotations.firstIndex(where: predicate) { + let dragAllowed = tryBeginDragging(&draggedAnnotations, idx: idx) + guard dragAllowed else { + return false + } + + draggedAnnotationIndex = idx + return true + } + + /// Then, try to start dragging from the main set of annotations. + if let idx = mainAnnotations.lastIndex(where: predicate) { + let dragAllowed = tryBeginDragging(&mainAnnotations, idx: idx) + guard dragAllowed else { + return false + } + + insertDraggedLayerAndSource() + + let annotation = mainAnnotations.remove(at: idx) + draggedAnnotations.append(annotation) + draggedAnnotationIndex = draggedAnnotations.endIndex - 1 + syncLayerOnce.reset() + return true + } + + return false + } + + private func insertDraggedLayerAndSource() { + insertDraggedLayerAndSourceOnce { + let source = GeoJSONSource(id: dragId) + let layer = Traits.makeLayer(id: dragId) + do { + try style.addSource(source) + try style.addPersistentLayer(layer, layerPosition: .above(id)) + } catch { + Log.error(forMessage: "Add drag source/layer \(error)", category: "Annotations") + } + } + } + + func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) { + guard !isSwiftUI, + let draggedAnnotationIndex, + draggedAnnotationIndex < draggedAnnotations.endIndex + else { + return + } + + let currentGeometry = draggedAnnotations[draggedAnnotationIndex]._geometry + guard let geometry = offsetCalculator.geometry(for: translation, from: currentGeometry) else { return } + draggedAnnotations[draggedAnnotationIndex]._geometry = geometry + + callDragHandler(\.dragChangeHandler, context: context) + } + + func handleDragEnd(context: MapContentGestureContext) { + guard !isSwiftUI else { return } + callDragHandler(\.dragEndHandler, context: context) + draggedAnnotationIndex = nil + } + + private func callDragHandler( + _ keyPath: KeyPath Void)?>, + context: MapContentGestureContext + ) { + guard let draggedAnnotationIndex, draggedAnnotationIndex < draggedAnnotations.endIndex else { + return + } + + if let handler = draggedAnnotations[draggedAnnotationIndex][keyPath: keyPath] { + var copy = draggedAnnotations[draggedAnnotationIndex] + handler(©, context) + draggedAnnotations[draggedAnnotationIndex] = copy + } + } +} diff --git a/Sources/MapboxMaps/Annotations/AnnotationManagerTraits.swift b/Sources/MapboxMaps/Annotations/AnnotationManagerTraits.swift new file mode 100644 index 000000000000..50b19e3f1f22 --- /dev/null +++ b/Sources/MapboxMaps/Annotations/AnnotationManagerTraits.swift @@ -0,0 +1,64 @@ +protocol AnnotationManagerTraits { + associatedtype AnnotationType: Annotation & AnnotationInternal & Equatable + associatedtype LayerType: Layer + associatedtype OffsetCalculator: OffsetGeometryCalculator where OffsetCalculator.GeometryType == AnnotationType.GeometryType + + typealias UpdateOffset = (inout AnnotationType, CGPoint) -> Bool + + static func makeLayer(id: String) -> LayerType + static var tag: String { get } +} + +struct PointAnnotationManagerTraits: AnnotationManagerTraits { + typealias OffsetCalculator = OffsetPointCalculator + typealias AnnotationType = PointAnnotation + typealias LayerType = SymbolLayer + + static func makeLayer(id: String) -> SymbolLayer { + var layer = SymbolLayer(id: id, source: id) + // Show all icons and texts by default in point annotations. + layer.iconAllowOverlap = .constant(true) + layer.textAllowOverlap = .constant(true) + layer.iconIgnorePlacement = .constant(true) + layer.textIgnorePlacement = .constant(true) + return layer + } + + static let tag = "PointAnnotationManager" +} + +struct CircleAnnotationManagerTraits: AnnotationManagerTraits { + typealias OffsetCalculator = OffsetPointCalculator + typealias AnnotationType = CircleAnnotation + typealias LayerType = CircleLayer + + static func makeLayer(id: String) -> CircleLayer { + CircleLayer(id: id, source: id) + } + + static let tag = "CircleAnnotationManager" +} + +struct PolygonAnnotationManagerTraits: AnnotationManagerTraits { + typealias OffsetCalculator = OffsetPolygonCalculator + typealias AnnotationType = PolygonAnnotation + typealias LayerType = FillLayer + + static func makeLayer(id: String) -> FillLayer { + FillLayer(id: id, source: id) + } + + static let tag = "PolygonAnnotationManager" +} + +struct PolylineAnnotationManagerTraits: AnnotationManagerTraits { + typealias OffsetCalculator = OffsetLineStringCalculator + typealias AnnotationType = PolylineAnnotation + typealias LayerType = LineLayer + + static func makeLayer(id: String) -> LineLayer { + LineLayer(id: id, source: id) + } + + static let tag = "PolylineAnnotationManager" +} diff --git a/Sources/MapboxMaps/Annotations/AnnotationOrchestrator.swift b/Sources/MapboxMaps/Annotations/AnnotationOrchestrator.swift index a4502ad1dbcc..91245c92e96b 100644 --- a/Sources/MapboxMaps/Annotations/AnnotationOrchestrator.swift +++ b/Sources/MapboxMaps/Annotations/AnnotationOrchestrator.swift @@ -18,20 +18,37 @@ public protocol AnnotationManager: AnyObject { var slot: String? { get set } } -protocol AnnotationManagerInternal: AnnotationManager { - var allLayerIds: [String] { get } - - func destroy() - - func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool +struct AnnotationManagerParams { + let id: String + let layerPosition: LayerPosition? + let clusterOptions: ClusterOptions? +} - func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool +struct AnnotationManagerDeps { + let map: MapboxMapProtocol + let style: StyleProtocol + let queryable: MapFeatureQueryable + let imagesManager: AnnotationImagesManagerProtocol + let displayLink: Signal - func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool + func makeOffsetCalculator() -> T { + return T.init(mapboxMap: map) + } - func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) + static func from(mapboxMap map: MapboxMap, displayLink: Signal) -> AnnotationManagerDeps { + AnnotationManagerDeps( + map: map, + style: map, + queryable: map, + imagesManager: AnnotationImagesManager(style: map), + displayLink: displayLink) + } +} - func handleDragEnd(context: MapContentGestureContext) +protocol AnnotationManagerInternal: AnnotationManager { + associatedtype Traits: AnnotationManagerTraits + var impl: AnnotationManagerImpl { get } + init(params: AnnotationManagerParams, deps: AnnotationManagerDeps) } struct AnnotationGestureHandlers { @@ -58,14 +75,27 @@ public protocol AnnotationInteractionDelegate: AnyObject { /// `AnnotationOrchestrator` provides a way to create annotation managers of different types. public final class AnnotationOrchestrator { - private let impl: AnnotationOrchestratorImplProtocol + private let deps: AnnotationManagerDeps - init(impl: AnnotationOrchestratorImplProtocol) { - self.impl = impl + init(deps: AnnotationManagerDeps) { + self.deps = deps } /// Dictionary of annotation managers keyed by their identifiers. - public var annotationManagersById: [String: AnnotationManager] { impl.annotationManagersById } + private(set) public var annotationManagersById = [String: AnnotationManager]() + + // TODO: Remove the following after migration to interactions. + @MutableRef + private(set) var managersByLayerId = [String: AnnotationManagerImplProtocol]() + private var annotationManagersImplsById = [String: AnnotationManagerImplProtocol]() { + didSet { + // calculate (layerId, manager) pairs + let pairs = annotationManagersImplsById.values.flatMap { manager in + manager.allLayerIds.map { ($0, manager) } + } + self.managersByLayerId = Dictionary(uniqueKeysWithValues: pairs) + } + } /// Creates a `PointAnnotationManager` which is used to manage a collection of /// `PointAnnotation`s. Annotations persist across style changes. If an annotation manager with @@ -86,8 +116,10 @@ public final class AnnotationOrchestrator { onClusterTap: ((AnnotationClusterGestureContext) -> Void)? = nil, onClusterLongPress: ((AnnotationClusterGestureContext) -> Void)? = nil ) -> PointAnnotationManager { - // swiftlint:disable:next force_cast - return impl.makePointAnnotationManager(id: id, layerPosition: layerPosition, clusterOptions: clusterOptions) as! PointAnnotationManager + let manager: PointAnnotationManager = make(AnnotationManagerParams(id: id, layerPosition: layerPosition, clusterOptions: clusterOptions), function: #function) + manager.onClusterTap = onClusterTap + manager.onClusterLongPress = onClusterLongPress + return manager } /// Creates a `PolygonAnnotationManager` which is used to manage a collection of @@ -101,8 +133,7 @@ public final class AnnotationOrchestrator { /// - Returns: An instance of `PolygonAnnotationManager` public func makePolygonAnnotationManager(id: String = String(UUID().uuidString.prefix(5)), layerPosition: LayerPosition? = nil) -> PolygonAnnotationManager { - // swiftlint:disable:next force_cast - return impl.makePolygonAnnotationManager(id: id, layerPosition: layerPosition) as! PolygonAnnotationManager + make(AnnotationManagerParams(id: id, layerPosition: layerPosition, clusterOptions: nil), function: #function) } /// Creates a `PolylineAnnotationManager` which is used to manage a collection of @@ -116,8 +147,7 @@ public final class AnnotationOrchestrator { /// - Returns: An instance of `PolylineAnnotationManager` public func makePolylineAnnotationManager(id: String = String(UUID().uuidString.prefix(5)), layerPosition: LayerPosition? = nil) -> PolylineAnnotationManager { - // swiftlint:disable:next force_cast - return impl.makePolylineAnnotationManager(id: id, layerPosition: layerPosition) as! PolylineAnnotationManager + make(AnnotationManagerParams(id: id, layerPosition: layerPosition, clusterOptions: nil), function: #function) } /// Creates a `CircleAnnotationManager` which is used to manage a collection of @@ -131,14 +161,32 @@ public final class AnnotationOrchestrator { /// - Returns: An instance of `CircleAnnotationManager` public func makeCircleAnnotationManager(id: String = String(UUID().uuidString.prefix(5)), layerPosition: LayerPosition? = nil) -> CircleAnnotationManager { - // swiftlint:disable:next force_cast - return impl.makeCircleAnnotationManager(id: id, layerPosition: layerPosition) as! CircleAnnotationManager + make(AnnotationManagerParams(id: id, layerPosition: layerPosition, clusterOptions: nil), function: #function) + } + + func make(_ params: AnnotationManagerParams, function: StaticString = #function) -> Manager { + removeAnnotationManager(withId: params.id, warnIfRemoved: true, function: #function) + let annotationManager = Manager(params: params, deps: deps) + annotationManagersById[params.id] = annotationManager + annotationManagersImplsById[params.id] = annotationManager.impl + return annotationManager } /// Removes an annotation manager, this will remove the underlying layer and source from the style. /// A removed annotation manager will not be able to reuse anymore, you will need to create new annotation manger to add annotations. /// - Parameter id: Identifer of annotation manager to remove public func removeAnnotationManager(withId id: String) { - impl.removeAnnotationManager(withId: id) + removeAnnotationManager(withId: id, warnIfRemoved: false, function: #function) + } + + private func removeAnnotationManager(withId id: String, warnIfRemoved: Bool, function: StaticString = #function) { + let manager = annotationManagersById.removeValue(forKey: id) + annotationManagersImplsById.removeValue(forKey: id)?.destroy() + + if let manager, warnIfRemoved { + Log.warning( + forMessage: "\(type(of: manager)) with id \(id) was removed implicitly when invoking \(function) with the same id.", + category: "Annotations") + } } } diff --git a/Sources/MapboxMaps/Annotations/AnnotationOrchestratorImpl.swift b/Sources/MapboxMaps/Annotations/AnnotationOrchestratorImpl.swift deleted file mode 100644 index 4210952a0f68..000000000000 --- a/Sources/MapboxMaps/Annotations/AnnotationOrchestratorImpl.swift +++ /dev/null @@ -1,137 +0,0 @@ -import Foundation -import UIKit -@_implementationOnly import MapboxCommon_Private - -internal protocol AnnotationOrchestratorImplProtocol: AnyObject { - var managersByLayerId: [String: AnnotationManagerInternal] { get } - var annotationManagersById: [String: AnnotationManager] { get } - func makePointAnnotationManager(id: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions?) -> AnnotationManagerInternal - func makePolygonAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal - func makePolylineAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal - func makeCircleAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal - func removeAnnotationManager(withId id: String) -} - -final class AnnotationOrchestratorImpl: NSObject, AnnotationOrchestratorImplProtocol { - private(set) var managersByLayerId: [String: AnnotationManagerInternal] = [:] - - private let factory: AnnotationManagerFactoryProtocol - - init(factory: AnnotationManagerFactoryProtocol) { - self.factory = factory - super.init() - } - - /// Dictionary of annotation managers keyed by their identifiers. - var annotationManagersById: [String: AnnotationManager] { annotationManagersByIdInternal } - - private var annotationManagersByIdInternal = [String: AnnotationManagerInternal]() { - didSet { - // calculate (layerId, manager) pairs - let pairs = annotationManagersByIdInternal.values.flatMap { manager in - manager.allLayerIds.map { ($0, manager) } - } - self.managersByLayerId = Dictionary(uniqueKeysWithValues: pairs) - } - } - - /// Creates a `PointAnnotationManager` which is used to manage a collection of - /// `PointAnnotation`s. Annotations persist across style changes. If an annotation manager with - /// the same `id` has already been created, the old one will be removed as if - /// `removeAnnotationManager(withId:)` had been called. `AnnotationOrchestrator` - /// keeps a strong reference to any `PointAnnotationManager` until it is removed. - /// - Parameters: - /// - id: Optional string identifier for this manager. - /// - layerPosition: Optionally set the `LayerPosition` of the layer managed. - /// - clusterOptions: Optionally set the `ClusterOptions` to cluster the Point Annotations - /// - Returns: An instance of `PointAnnotationManager` - func makePointAnnotationManager( - id: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions? - ) -> AnnotationManagerInternal { - removeAnnotationManager(withId: id, warnIfRemoved: true, function: #function) - let annotationManager = factory.makePointAnnotationManager( - id: id, - layerPosition: layerPosition, - clusterOptions: clusterOptions) - annotationManagersByIdInternal[id] = annotationManager - return annotationManager - } - - /// Creates a `PolygonAnnotationManager` which is used to manage a collection of - /// `PolygonAnnotation`s. Annotations persist across style changes. If an annotation manager with - /// the same `id` has already been created, the old one will be removed as if - /// `removeAnnotationManager(withId:)` had been called. `AnnotationOrchestrator` - /// keeps a strong reference to any `PolygonAnnotationManager` until it is removed. - /// - Parameters: - /// - id: Optional string identifier for this manager.. - /// - layerPosition: Optionally set the `LayerPosition` of the layer managed. - /// - Returns: An instance of `PolygonAnnotationManager` - func makePolygonAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal { - removeAnnotationManager(withId: id, warnIfRemoved: true, function: #function) - let annotationManager = factory.makePolygonAnnotationManager( - id: id, - layerPosition: layerPosition) - annotationManagersByIdInternal[id] = annotationManager - - return annotationManager - } - - /// Creates a `PolylineAnnotationManager` which is used to manage a collection of - /// `PolylineAnnotation`s. Annotations persist across style changes. If an annotation manager with - /// the same `id` has already been created, the old one will be removed as if - /// `removeAnnotationManager(withId:)` had been called. `AnnotationOrchestrator` - /// keeps a strong reference to any `PolylineAnnotationManager` until it is removed. - /// - Parameters: - /// - id: Optional string identifier for this manager. - /// - layerPosition: Optionally set the `LayerPosition` of the layer managed. - /// - Returns: An instance of `PolylineAnnotationManager` - func makePolylineAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal { - removeAnnotationManager(withId: id, warnIfRemoved: true, function: #function) - let annotationManager = factory.makePolylineAnnotationManager( - id: id, - layerPosition: layerPosition) - annotationManagersByIdInternal[id] = annotationManager - return annotationManager - } - - /// Creates a `CircleAnnotationManager` which is used to manage a collection of - /// `CircleAnnotation`s. Annotations persist across style changes. If an annotation manager with - /// the same `id` has already been created, the old one will be removed as if - /// `removeAnnotationManager(withId:)` had been called. `AnnotationOrchestrator` - /// keeps a strong reference to any `CircleAnnotationManager` until it is removed. - /// - Parameters: - /// - id: Optional string identifier for this manager. - /// - layerPosition: Optionally set the `LayerPosition` of the layer managed. - /// - Returns: An instance of `CircleAnnotationManager` - func makeCircleAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal { - removeAnnotationManager(withId: id, warnIfRemoved: true, function: #function) - let annotationManager = factory.makeCircleAnnotationManager( - id: id, - layerPosition: layerPosition) - annotationManagersByIdInternal[id] = annotationManager - return annotationManager - } - - /// Removes an annotation manager, this will remove the underlying layer and source from the style. - /// A removed annotation manager will not be able to reuse anymore, you will need to create new annotation manger to add annotations. - /// - Parameter id: Identifer of annotation manager to remove - public func removeAnnotationManager(withId id: String) { - removeAnnotationManager(withId: id, warnIfRemoved: false, function: #function) - } - - private func removeAnnotationManager(withId id: String, warnIfRemoved: Bool, function: StaticString = #function) { - guard let annotationManager = annotationManagersByIdInternal.removeValue(forKey: id) else { - return - } - annotationManager.destroy() - if warnIfRemoved { - Log.warning( - forMessage: "\(type(of: annotationManager)) with id \(id) was removed implicitly when invoking \(function) with the same id.", - category: "Annotations") - } - } -} diff --git a/Sources/MapboxMaps/Annotations/Generated/CircleAnnotation.swift b/Sources/MapboxMaps/Annotations/Generated/CircleAnnotation.swift index c348e7fdbe47..af947f7f1484 100644 --- a/Sources/MapboxMaps/Annotations/Generated/CircleAnnotation.swift +++ b/Sources/MapboxMaps/Annotations/Generated/CircleAnnotation.swift @@ -1,19 +1,24 @@ // This file is generated. import UIKit -public struct CircleAnnotation: Annotation, Equatable { +public struct CircleAnnotation: Annotation, Equatable, AnnotationInternal { /// Identifier for this annotation internal(set) public var id: String /// The geometry backing this annotation public var geometry: Geometry { - return .point(point) + .point(point) } - /// The point backing this annotation + /// The Point backing this annotation public var point: Point + var _geometry: Point { + get { point } + set { point = newValue } + } + /// Toggles the annotation's selection state. /// If the annotation is deselected, it becomes selected. /// If the annotation is selected, it becomes deselected. @@ -272,7 +277,7 @@ extension CircleAnnotation { } @available(iOS 13.0, *) -extension CircleAnnotation: MapContent, PrimitiveMapContent, MapContentAnnotation { +extension CircleAnnotation: MapContent, PrimitiveMapContent { func visit(_ node: MapContentNode) { CircleAnnotationGroup { self }.visit(node) } diff --git a/Sources/MapboxMaps/Annotations/Generated/CircleAnnotationManager.swift b/Sources/MapboxMaps/Annotations/Generated/CircleAnnotationManager.swift index b55d626e393f..aac13d65bf19 100644 --- a/Sources/MapboxMaps/Annotations/Generated/CircleAnnotationManager.swift +++ b/Sources/MapboxMaps/Annotations/Generated/CircleAnnotationManager.swift @@ -1,44 +1,25 @@ // This file is generated. -import Foundation -import os -@_implementationOnly import MapboxCommon_Private -/// An instance of `CircleAnnotationManager` is responsible for a collection of `CircleAnnotation`s. -public class CircleAnnotationManager: AnnotationManagerInternal { - typealias OffsetCalculatorType = OffsetPointCalculator - - public var sourceId: String { id } - - public var layerId: String { id } - private var dragId: String { "\(id)_drag" } +/// An instance of `CircleAnnotationManager` is responsible for a collection of `CircleAnnotation`s. +public class CircleAnnotationManager: AnnotationManager, AnnotationManagerInternal, AnnotationManagerImplDelegate { + typealias Impl = AnnotationManagerImpl - public let id: String + public var sourceId: String { impl.id } + public var layerId: String { impl.id } + public var id: String { impl.id } - var layerPosition: LayerPosition? { - didSet { - do { - try style.moveLayer(withId: layerId, to: layerPosition ?? .default) - } catch { - Log.error(forMessage: "Failed to mover layer to a new position. Error: \(error)", category: "Annotations") - } - } - } + let impl: AnnotationManagerImpl /// The collection of ``CircleAnnotation`` being managed. /// /// Each annotation must have a unique identifier. Duplicate IDs will cause only the first annotation to be displayed, while the rest will be ignored. public var annotations: [CircleAnnotation] { - get { mainAnnotations + draggedAnnotations } - set { - mainAnnotations = newValue - mainAnnotations.removeDuplicates() - draggedAnnotations.removeAll(keepingCapacity: true) - draggedAnnotationIndex = nil - } + get { impl.annotations } + set { impl.annotations = newValue } } /// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager. - /// - NOTE: This annotation manager listens to tap events via the `GestureManager.singleTapGestureRecognizer`. + /// - NOTE: This annotation manager listens to tap events via the ``GestureManager/singleTapGestureRecognizer``. @available(*, deprecated, message: "Use tapHandler property of Annotation") public weak var delegate: AnnotationInteractionDelegate? { get { _delegate } @@ -46,253 +27,53 @@ public class CircleAnnotationManager: AnnotationManagerInternal { } private weak var _delegate: AnnotationInteractionDelegate? - // Deps - private let style: StyleProtocol - private let offsetCalculator: OffsetCalculatorType - - // Private state - - /// Currently displayed (synced) annotations. - private var displayedAnnotations: [CircleAnnotation] = [] - - /// Updated, non-moved annotations. On next display link they will be diffed with `displayedAnnotations` and updated. - private var mainAnnotations = [CircleAnnotation]() { - didSet { syncSourceOnce.reset() } - } - - /// When annotation is moved for the first time, it migrates to this array from mainAnnotations. - private var draggedAnnotations = [CircleAnnotation]() { - didSet { - if insertDraggedLayerAndSourceOnce.happened { - // Update dragged annotation only when the drag layer is created. - syncDragSourceOnce.reset() - } - } + required init(params: AnnotationManagerParams, deps: AnnotationManagerDeps) { + self.impl = .init(params: params, deps: deps) + impl.delegate = self } - /// Storage for common layer properties - var layerProperties: [String: Any] = [:] { - didSet { - syncLayerOnce.reset() - } - } - - /// The keys of the style properties that were set during the previous sync. - /// Used to identify which styles need to be restored to their default values in - /// the subsequent sync. - private var previouslySetLayerPropertyKeys: Set = [] - - private var draggedAnnotationIndex: Array.Index? - private var destroyOnce = Once() - private var syncSourceOnce = Once(happened: true) - private var syncDragSourceOnce = Once(happened: true) - private var syncLayerOnce = Once(happened: true) - private var insertDraggedLayerAndSourceOnce = Once() - private var displayLinkToken: AnyCancelable? - - var allLayerIds: [String] { [layerId, dragId] } - - /// In SwiftUI isDraggable and isSelected are disabled. - var isSwiftUI = false - - init(id: String, - style: StyleProtocol, - layerPosition: LayerPosition?, - displayLink: Signal, - offsetCalculator: OffsetCalculatorType - ) { - self.id = id - self.style = style - self.offsetCalculator = offsetCalculator - - do { - // Add the source with empty `data` property - let source = GeoJSONSource(id: sourceId) - try style.addSource(source) - - // Add the correct backing layer for this annotation type - let layer = CircleLayer(id: layerId, source: sourceId) - try style.addPersistentLayer(layer, layerPosition: layerPosition) - } catch { - Log.error( - forMessage: "Failed to create source / layer in CircleAnnotationManager. Error: \(error)", - category: "Annotations") - } - - displayLinkToken = displayLink.observe { [weak self] in - self?.syncSourceAndLayerIfNeeded() - } - } - - var idsMap = [AnyHashable: String]() - - func set(newAnnotations: [(AnyHashable, CircleAnnotation)]) { - var resolvedAnnotations = [CircleAnnotation]() - newAnnotations.forEach { elementId, annotation in - var annotation = annotation - let stringId = idsMap[elementId] ?? annotation.id - idsMap[elementId] = stringId - annotation.id = stringId - annotation.isDraggable = false - annotation.isSelected = false - resolvedAnnotations.append(annotation) - } - annotations = resolvedAnnotations - } - - func destroy() { - guard destroyOnce.continueOnce() else { return } - - displayLinkToken?.cancel() - - func wrapError(_ what: String, _ body: () throws -> Void) { - do { - try body() - } catch { - Log.warning( - forMessage: "Failed to remove \(what) for CircleAnnotationManager with id \(id) due to error: \(error)", - category: "Annotations") - } - } - - wrapError("layer") { - try style.removeLayer(withId: layerId) - } - - wrapError("source") { - try style.removeSource(withId: sourceId) - } - - if insertDraggedLayerAndSourceOnce.happened { - wrapError("drag source and layer") { - try style.removeLayer(withId: dragId) - try style.removeSource(withId: dragId) - } - } - } - - // MARK: - Sync annotations to map - - private func syncSource() { - guard syncSourceOnce.continueOnce() else { return } - - let diff = mainAnnotations.diff(from: displayedAnnotations, id: \.id) - syncLayerOnce.reset(if: !diff.isEmpty) - style.apply(annotationsDiff: diff, sourceId: sourceId, feature: \.feature) - displayedAnnotations = mainAnnotations - } - - private func syncDragSource() { - guard syncDragSourceOnce.continueOnce() else { return } - - let fc = FeatureCollection(features: draggedAnnotations.map(\.feature)) - style.updateGeoJSONSource(withId: dragId, geoJSON: .featureCollection(fc)) - } - - private func syncLayer() { - guard syncLayerOnce.continueOnce() else { return } - - // Construct the properties dictionary from the annotations - let dataDrivenLayerPropertyKeys = Set(annotations.flatMap(\.layerProperties.keys)) - let dataDrivenProperties = Dictionary( - uniqueKeysWithValues: dataDrivenLayerPropertyKeys - .map { (key) -> (String, Any) in - (key, ["get", key, ["get", "layerProperties"]] as [Any]) - }) - - // Merge the common layer properties - let newLayerProperties = dataDrivenProperties.merging(layerProperties, uniquingKeysWith: { $1 }) - - // Construct the properties dictionary to reset any properties that are no longer used - let unusedPropertyKeys = previouslySetLayerPropertyKeys.subtracting(newLayerProperties.keys) - let unusedProperties = Dictionary(uniqueKeysWithValues: unusedPropertyKeys.map { (key) -> (String, Any) in - (key, StyleManager.layerPropertyDefaultValue(for: .circle, property: key).value) - }) - - // Store the new set of property keys - previouslySetLayerPropertyKeys = Set(newLayerProperties.keys) - - // Merge the new and unused properties - let allLayerProperties = newLayerProperties.merging(unusedProperties, uniquingKeysWith: { $1 }) - - // make a single call into MapboxCoreMaps to set layer properties - do { - try style.setLayerProperties(for: layerId, properties: allLayerProperties) - if !draggedAnnotations.isEmpty { - try style.setLayerProperties(for: dragId, properties: allLayerProperties) - } - } catch { - Log.error( - forMessage: "Could not set layer properties in CircleAnnotationManager due to error \(error)", - category: "Annotations") - } + func didTap(_ annotations: [Annotation]) { + _delegate?.annotationManager(self, didDetectTappedAnnotations: annotations) } - func syncSourceAndLayerIfNeeded() { - guard !destroyOnce.happened else { return } - - OSLog.platform.withIntervalSignpost(SignpostName.mapViewDisplayLink, "Participant: CircleAnnotationManager") { - syncSource() - syncDragSource() - syncLayer() - } - } + func syncImages() {} + func removeAllImages() {} // MARK: - Common layer properties /// Controls the intensity of light emitted on the source features. /// Default value: 0. Minimum value: 0. public var circleEmissiveStrength: Double? { - get { - return layerProperties["circle-emissive-strength"] as? Double - } - set { - layerProperties["circle-emissive-strength"] = newValue - } + get { impl.layerProperties["circle-emissive-strength"] as? Double } + set { impl.layerProperties["circle-emissive-strength"] = newValue } } /// Orientation of circle when map is pitched. /// Default value: "viewport". public var circlePitchAlignment: CirclePitchAlignment? { - get { - return layerProperties["circle-pitch-alignment"].flatMap { $0 as? String }.flatMap(CirclePitchAlignment.init(rawValue:)) - } - set { - layerProperties["circle-pitch-alignment"] = newValue?.rawValue - } + get { impl.layerProperties["circle-pitch-alignment"].flatMap { $0 as? String }.flatMap(CirclePitchAlignment.init(rawValue:)) } + set { impl.layerProperties["circle-pitch-alignment"] = newValue?.rawValue } } /// Controls the scaling behavior of the circle when the map is pitched. /// Default value: "map". public var circlePitchScale: CirclePitchScale? { - get { - return layerProperties["circle-pitch-scale"].flatMap { $0 as? String }.flatMap(CirclePitchScale.init(rawValue:)) - } - set { - layerProperties["circle-pitch-scale"] = newValue?.rawValue - } + get { impl.layerProperties["circle-pitch-scale"].flatMap { $0 as? String }.flatMap(CirclePitchScale.init(rawValue:)) } + set { impl.layerProperties["circle-pitch-scale"] = newValue?.rawValue } } /// The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively. /// Default value: [0,0]. public var circleTranslate: [Double]? { - get { - return layerProperties["circle-translate"] as? [Double] - } - set { - layerProperties["circle-translate"] = newValue - } + get { impl.layerProperties["circle-translate"] as? [Double] } + set { impl.layerProperties["circle-translate"] = newValue } } /// Controls the frame of reference for `circle-translate`. /// Default value: "map". public var circleTranslateAnchor: CircleTranslateAnchor? { - get { - return layerProperties["circle-translate-anchor"].flatMap { $0 as? String }.flatMap(CircleTranslateAnchor.init(rawValue:)) - } - set { - layerProperties["circle-translate-anchor"] = newValue?.rawValue - } + get { impl.layerProperties["circle-translate-anchor"].flatMap { $0 as? String }.flatMap(CircleTranslateAnchor.init(rawValue:)) } + set { impl.layerProperties["circle-translate-anchor"] = newValue?.rawValue } } /// Slot for the underlying layer. @@ -300,135 +81,10 @@ public class CircleAnnotationManager: AnnotationManagerInternal { /// Use this property to position the annotations relative to other map features if you use Mapbox Standard Style. /// See for more info. public var slot: String? { - get { - return layerProperties["slot"] as? String - } - set { - layerProperties["slot"] = newValue - } - } - - // MARK: - User interaction handling - - func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - - guard let featureId = feature.identifier?.string else { return false } - - let tappedIndex = annotations.firstIndex { $0.id == featureId } - guard let tappedIndex else { return false } - var tappedAnnotation = annotations[tappedIndex] - - tappedAnnotation.isSelected.toggle() - - if !isSwiftUI { - // In-place update of annotations is not supported in SwiftUI. - // Use the .onTapGesture {} to update annotations on call side. - self.annotations[tappedIndex] = tappedAnnotation - } - - _delegate?.annotationManager( - self, - didDetectTappedAnnotations: [tappedAnnotation]) - - return tappedAnnotation.tapHandler?(context) ?? false + get { impl.layerProperties["slot"] as? String } + set { impl.layerProperties["slot"] = newValue } } - func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - guard let featureId = feature.identifier?.string else { return false } - - return annotations.first { $0.id == featureId }?.longPressHandler?(context) ?? false - } - - func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool { - guard !isSwiftUI else { return false } - - func predicate(annotation: CircleAnnotation) -> Bool { - annotation.id == featureId && annotation.isDraggable - } - - func tryBeginDragging(_ annotations: inout [CircleAnnotation], idx: Int) -> Bool { - var annotation = annotations[idx] - // If no drag handler set, the dragging is allowed - let dragAllowed = annotation.dragBeginHandler?(&annotation, context) ?? true - annotations[idx] = annotation - return dragAllowed - } - - /// First, try to drag annotations that are already on the dragging layer. - if let idx = draggedAnnotations.firstIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&draggedAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - draggedAnnotationIndex = idx - return true - } - - /// Then, try to start dragging from the main set of annotations. - if let idx = mainAnnotations.lastIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&mainAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - insertDraggedLayerAndSource() - - let annotation = mainAnnotations.remove(at: idx) - draggedAnnotations.append(annotation) - draggedAnnotationIndex = draggedAnnotations.endIndex - 1 - return true - } - - return false - } - - private func insertDraggedLayerAndSource() { - insertDraggedLayerAndSourceOnce { - let source = GeoJSONSource(id: dragId) - let layer = CircleLayer(id: dragId, source: dragId) - do { - try style.addSource(source) - try style.addPersistentLayer(layer, layerPosition: .above(layerId)) - } catch { - Log.error(forMessage: "Add drag source/layer \(error)", category: "Annotations") - } - } - } - - func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) { - guard !isSwiftUI, - let draggedAnnotationIndex, - draggedAnnotationIndex < draggedAnnotations.endIndex, - let point = offsetCalculator.geometry(for: translation, from: draggedAnnotations[draggedAnnotationIndex].point) else { - return - } - - draggedAnnotations[draggedAnnotationIndex].point = point - - callDragHandler(\.dragChangeHandler, context: context) - } - - func handleDragEnd(context: MapContentGestureContext) { - guard !isSwiftUI else { return } - callDragHandler(\.dragEndHandler, context: context) - draggedAnnotationIndex = nil - } - - private func callDragHandler( - _ keyPath: KeyPath Void)?>, - context: MapContentGestureContext - ) { - guard let draggedAnnotationIndex, draggedAnnotationIndex < draggedAnnotations.endIndex else { - return - } - - if let handler = draggedAnnotations[draggedAnnotationIndex][keyPath: keyPath] { - var copy = draggedAnnotations[draggedAnnotationIndex] - handler(©, context) - draggedAnnotations[draggedAnnotationIndex] = copy - } - } } // End of generated file. diff --git a/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift b/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift index 2080f42739a7..ae9acfd11e7b 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift @@ -1,19 +1,24 @@ // This file is generated. import UIKit -public struct PointAnnotation: Annotation, Equatable { +public struct PointAnnotation: Annotation, Equatable, AnnotationInternal { /// Identifier for this annotation internal(set) public var id: String /// The geometry backing this annotation public var geometry: Geometry { - return .point(point) + .point(point) } - /// The point backing this annotation + /// The Point backing this annotation public var point: Point + var _geometry: Point { + get { point } + set { point = newValue } + } + /// Toggles the annotation's selection state. /// If the annotation is deselected, it becomes selected. /// If the annotation is selected, it becomes deselected. @@ -586,7 +591,7 @@ extension PointAnnotation { } @available(iOS 13.0, *) -extension PointAnnotation: MapContent, PrimitiveMapContent, MapContentAnnotation { +extension PointAnnotation: MapContent, PrimitiveMapContent { func visit(_ node: MapContentNode) { PointAnnotationGroup { self }.visit(node) } diff --git a/Sources/MapboxMaps/Annotations/Generated/PointAnnotationManager.swift b/Sources/MapboxMaps/Annotations/Generated/PointAnnotationManager.swift index 54445560fa41..e7efc2561167 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PointAnnotationManager.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PointAnnotationManager.swift @@ -1,46 +1,25 @@ // This file is generated. -import Foundation -import os -@_implementationOnly import MapboxCommon_Private -/// An instance of `PointAnnotationManager` is responsible for a collection of `PointAnnotation`s. -public class PointAnnotationManager: AnnotationManagerInternal { - typealias OffsetCalculatorType = OffsetPointCalculator - - public var sourceId: String { id } - - public var layerId: String { id } - - private var dragId: String { "\(id)_drag" } - private var clusterId: String { "mapbox-iOS-cluster-circle-layer-manager-\(id)" } +/// An instance of `PointAnnotationManager` is responsible for a collection of `PointAnnotation`s. +public class PointAnnotationManager: AnnotationManager, AnnotationManagerInternal, AnnotationManagerImplDelegate { + typealias Impl = AnnotationManagerImpl - public let id: String + public var sourceId: String { impl.id } + public var layerId: String { impl.id } + public var id: String { impl.id } - var layerPosition: LayerPosition? { - didSet { - do { - try style.moveLayer(withId: layerId, to: layerPosition ?? .default) - } catch { - Log.error(forMessage: "Failed to mover layer to a new position. Error: \(error)", category: "Annotations") - } - } - } + let impl: AnnotationManagerImpl /// The collection of ``PointAnnotation`` being managed. /// /// Each annotation must have a unique identifier. Duplicate IDs will cause only the first annotation to be displayed, while the rest will be ignored. public var annotations: [PointAnnotation] { - get { mainAnnotations + draggedAnnotations } - set { - mainAnnotations = newValue - mainAnnotations.removeDuplicates() - draggedAnnotations.removeAll(keepingCapacity: true) - draggedAnnotationIndex = nil - } + get { impl.annotations } + set { impl.annotations = newValue } } /// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager. - /// - NOTE: This annotation manager listens to tap events via the `GestureManager.singleTapGestureRecognizer`. + /// - NOTE: This annotation manager listens to tap events via the ``GestureManager/singleTapGestureRecognizer``. @available(*, deprecated, message: "Use tapHandler property of Annotation") public weak var delegate: AnnotationInteractionDelegate? { get { _delegate } @@ -48,242 +27,35 @@ public class PointAnnotationManager: AnnotationManagerInternal { } private weak var _delegate: AnnotationInteractionDelegate? - // Deps - private let style: StyleProtocol - private let offsetCalculator: OffsetCalculatorType - - // Private state - - /// Currently displayed (synced) annotations. - private var displayedAnnotations: [PointAnnotation] = [] + required init(params: AnnotationManagerParams, deps: AnnotationManagerDeps) { + self.impl = .init(params: params, deps: deps) + self.imagesManager = deps.imagesManager - /// Updated, non-moved annotations. On next display link they will be diffed with `displayedAnnotations` and updated. - private var mainAnnotations = [PointAnnotation]() { - didSet { syncSourceOnce.reset() } + impl.delegate = self + imagesManager.register(imagesConsumer: self) } - /// When annotation is moved for the first time, it migrates to this array from mainAnnotations. - private var draggedAnnotations = [PointAnnotation]() { - didSet { - if insertDraggedLayerAndSourceOnce.happened { - // Update dragged annotation only when the drag layer is created. - syncDragSourceOnce.reset() - } - } + func didTap(_ annotations: [Annotation]) { + _delegate?.annotationManager(self, didDetectTappedAnnotations: annotations) } - /// Storage for common layer properties - var layerProperties: [String: Any] = [:] { - didSet { - syncLayerOnce.reset() - } + /// Handles tap gesture on cluster. + public var onClusterTap: ((AnnotationClusterGestureContext) -> Void)? { + get { impl.onClusterTap } + set { impl.onClusterTap = newValue } } - /// The keys of the style properties that were set during the previous sync. - /// Used to identify which styles need to be restored to their default values in - /// the subsequent sync. - private var previouslySetLayerPropertyKeys: Set = [] - - private var draggedAnnotationIndex: Array.Index? - private var destroyOnce = Once() - private var syncSourceOnce = Once(happened: true) - private var syncDragSourceOnce = Once(happened: true) - private var syncLayerOnce = Once(happened: true) - private var insertDraggedLayerAndSourceOnce = Once() - private var displayLinkToken: AnyCancelable? + /// Handles long press gesture on cluster. + public var onClusterLongPress: ((AnnotationClusterGestureContext) -> Void)? { + get { impl.onClusterLongPress } + set { impl.onClusterLongPress = newValue } + } /// List of images used by this ``PointAnnotationManager``. private(set) internal var allImages = Set() private let imagesManager: AnnotationImagesManagerProtocol - private var clusterOptions: ClusterOptions? - private let mapFeatureQueryable: MapFeatureQueryable - - public var onClusterTap: ((AnnotationClusterGestureContext) -> Void)? - public var onClusterLongPress: ((AnnotationClusterGestureContext) -> Void)? - var allLayerIds: [String] { [layerId, dragId, clusterId] } - - /// In SwiftUI isDraggable and isSelected are disabled. - var isSwiftUI = false - - init(id: String, - style: StyleProtocol, - layerPosition: LayerPosition?, - displayLink: Signal, - clusterOptions: ClusterOptions? = nil, - mapFeatureQueryable: MapFeatureQueryable, - imagesManager: AnnotationImagesManagerProtocol, - offsetCalculator: OffsetCalculatorType - ) { - self.id = id - self.style = style - self.offsetCalculator = offsetCalculator - - self.clusterOptions = clusterOptions - self.imagesManager = imagesManager - self.mapFeatureQueryable = mapFeatureQueryable - imagesManager.register(imagesConsumer: self) - do { - // Add the source with empty `data` property - var source = GeoJSONSource(id: sourceId) - - // Set cluster options and create clusters if clustering is enabled - if let clusterOptions = clusterOptions { - source.cluster = true - source.clusterRadius = clusterOptions.clusterRadius - source.clusterProperties = clusterOptions.clusterProperties - source.clusterMaxZoom = clusterOptions.clusterMaxZoom - source.clusterMinPoints = clusterOptions.clusterMinPoints - } - - try style.addSource(source) - - if let clusterOptions = clusterOptions { - createClusterLayers(clusterOptions: clusterOptions) - } - - // Add the correct backing layer for this annotation type - var layer = SymbolLayer(id: layerId, source: sourceId) - - // Show all icons and texts by default in point annotations. - layer.iconAllowOverlap = .constant(true) - layer.textAllowOverlap = .constant(true) - layer.iconIgnorePlacement = .constant(true) - layer.textIgnorePlacement = .constant(true) - try style.addPersistentLayer(layer, layerPosition: layerPosition) - } catch { - Log.error( - forMessage: "Failed to create source / layer in PointAnnotationManager. Error: \(error)", - category: "Annotations") - } - - displayLinkToken = displayLink.observe { [weak self] in - self?.syncSourceAndLayerIfNeeded() - } - } - - private func createClusterLayers(clusterOptions: ClusterOptions) { - let clusterLevelLayer = createClusterLevelLayer(clusterOptions: clusterOptions) - let clusterTextLayer = createClusterTextLayer(clusterOptions: clusterOptions) - do { - try addClusterLayer(clusterLayer: clusterLevelLayer) - try addClusterLayer(clusterLayer: clusterTextLayer) - } catch { - Log.error( - forMessage: "Failed to add cluster layer in PointAnnotationManager. Error: \(error)", - category: "Annotations") - } - } - - private func addClusterLayer(clusterLayer: Layer) throws { - guard style.layerExists(withId: clusterLayer.id) else { - try style.addPersistentLayer(clusterLayer, layerPosition: .default) - return - } - } - - private func createClusterLevelLayer(clusterOptions: ClusterOptions) -> CircleLayer { - let layedID = "mapbox-iOS-cluster-circle-layer-manager-" + id - var circleLayer = CircleLayer(id: layedID, source: sourceId) - circleLayer.circleColor = clusterOptions.circleColor - circleLayer.circleRadius = clusterOptions.circleRadius - circleLayer.filter = Exp(.has) { "point_count" } - return circleLayer - } - - private func createClusterTextLayer(clusterOptions: ClusterOptions) -> SymbolLayer { - let layerID = "mapbox-iOS-cluster-text-layer-manager-" + id - var symbolLayer = SymbolLayer(id: layerID, source: sourceId) - symbolLayer.textField = clusterOptions.textField - symbolLayer.textSize = clusterOptions.textSize - symbolLayer.textColor = clusterOptions.textColor - return symbolLayer - } - - private func destroyClusterLayers() { - do { - try style.removeLayer(withId: "mapbox-iOS-cluster-circle-layer-manager-" + id) - try style.removeLayer(withId: "mapbox-iOS-cluster-text-layer-manager-" + id) - } catch { - Log.error( - forMessage: "Failed to remove cluster layer in PointAnnotationManager. Error: \(error)", - category: "Annotations") - } - } - - var idsMap = [AnyHashable: String]() - - func set(newAnnotations: [(AnyHashable, PointAnnotation)]) { - var resolvedAnnotations = [PointAnnotation]() - newAnnotations.forEach { elementId, annotation in - var annotation = annotation - let stringId = idsMap[elementId] ?? annotation.id - idsMap[elementId] = stringId - annotation.id = stringId - annotation.isDraggable = false - annotation.isSelected = false - resolvedAnnotations.append(annotation) - } - annotations = resolvedAnnotations - } - - func destroy() { - guard destroyOnce.continueOnce() else { return } - - displayLinkToken?.cancel() - - if clusterOptions != nil { - destroyClusterLayers() - } - - func wrapError(_ what: String, _ body: () throws -> Void) { - do { - try body() - } catch { - Log.warning( - forMessage: "Failed to remove \(what) for PointAnnotationManager with id \(id) due to error: \(error)", - category: "Annotations") - } - } - - wrapError("layer") { - try style.removeLayer(withId: layerId) - } - - wrapError("source") { - try style.removeSource(withId: sourceId) - } - - if insertDraggedLayerAndSourceOnce.happened { - wrapError("drag source and layer") { - try style.removeLayer(withId: dragId) - try style.removeSource(withId: dragId) - } - } - - removeAllImages() - } - - // MARK: - Sync annotations to map - - private func syncSource() { - guard syncSourceOnce.continueOnce() else { return } - - let diff = mainAnnotations.diff(from: displayedAnnotations, id: \.id) - syncLayerOnce.reset(if: !diff.isEmpty) - style.apply(annotationsDiff: diff, sourceId: sourceId, feature: \.feature) - displayedAnnotations = mainAnnotations - } - - private func syncDragSource() { - guard syncDragSourceOnce.continueOnce() else { return } - - let fc = FeatureCollection(features: draggedAnnotations.map(\.feature)) - style.updateGeoJSONSource(withId: dragId, geoJSON: .featureCollection(fc)) - } - - private func syncLayer() { - guard syncLayerOnce.continueOnce() else { return } + func syncImages() { let newImages = Set(annotations.compactMap(\.image)) let newImageNames = Set(newImages.map(\.name)) let unusedImages = allImages.subtracting(newImageNames) @@ -292,358 +64,219 @@ public class PointAnnotationManager: AnnotationManagerInternal { allImages = newImageNames removeImages(unusedImages) + } - // Construct the properties dictionary from the annotations - let dataDrivenLayerPropertyKeys = Set(annotations.flatMap(\.layerProperties.keys)) - let dataDrivenProperties = Dictionary( - uniqueKeysWithValues: dataDrivenLayerPropertyKeys - .map { (key) -> (String, Any) in - (key, ["get", key, ["get", "layerProperties"]] as [Any]) - }) - - // Merge the common layer properties - let newLayerProperties = dataDrivenProperties.merging(layerProperties, uniquingKeysWith: { $1 }) - - // Construct the properties dictionary to reset any properties that are no longer used - let unusedPropertyKeys = previouslySetLayerPropertyKeys.subtracting(newLayerProperties.keys) - let unusedProperties = Dictionary(uniqueKeysWithValues: unusedPropertyKeys.map { (key) -> (String, Any) in - (key, StyleManager.layerPropertyDefaultValue(for: .symbol, property: key).value) - }) - - // Store the new set of property keys - previouslySetLayerPropertyKeys = Set(newLayerProperties.keys) - - // Merge the new and unused properties - let allLayerProperties = newLayerProperties.merging(unusedProperties, uniquingKeysWith: { $1 }) - - // make a single call into MapboxCoreMaps to set layer properties - do { - try style.setLayerProperties(for: layerId, properties: allLayerProperties) - if !draggedAnnotations.isEmpty { - try style.setLayerProperties(for: dragId, properties: allLayerProperties) - } - } catch { - Log.error( - forMessage: "Could not set layer properties in PointAnnotationManager due to error \(error)", - category: "Annotations") + func addImages(_ images: Set) { + for image in images { + imagesManager.addImage(image.image, id: image.name, sdf: false, contentInsets: .zero) } } - func syncSourceAndLayerIfNeeded() { - guard !destroyOnce.happened else { return } - - OSLog.platform.withIntervalSignpost(SignpostName.mapViewDisplayLink, "Participant: PointAnnotationManager") { - syncSource() - syncDragSource() - syncLayer() + func removeImages(_ names: Set) { + for imageName in names { + imagesManager.removeImage(imageName) } } + func removeAllImages() { + let imagesToRemove = allImages + allImages.removeAll() + removeImages(imagesToRemove) + } + // MARK: - Common layer properties /// If true, the icon will be visible even if it collides with other previously drawn symbols. /// Default value: false. public var iconAllowOverlap: Bool? { - get { - return layerProperties["icon-allow-overlap"] as? Bool - } - set { - layerProperties["icon-allow-overlap"] = newValue - } + get { impl.layerProperties["icon-allow-overlap"] as? Bool } + set { impl.layerProperties["icon-allow-overlap"] = newValue } } /// If true, other symbols can be visible even if they collide with the icon. /// Default value: false. public var iconIgnorePlacement: Bool? { - get { - return layerProperties["icon-ignore-placement"] as? Bool - } - set { - layerProperties["icon-ignore-placement"] = newValue - } + get { impl.layerProperties["icon-ignore-placement"] as? Bool } + set { impl.layerProperties["icon-ignore-placement"] = newValue } } /// If true, the icon may be flipped to prevent it from being rendered upside-down. /// Default value: false. public var iconKeepUpright: Bool? { - get { - return layerProperties["icon-keep-upright"] as? Bool - } - set { - layerProperties["icon-keep-upright"] = newValue - } + get { impl.layerProperties["icon-keep-upright"] as? Bool } + set { impl.layerProperties["icon-keep-upright"] = newValue } } /// If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not. /// Default value: false. public var iconOptional: Bool? { - get { - return layerProperties["icon-optional"] as? Bool - } - set { - layerProperties["icon-optional"] = newValue - } + get { impl.layerProperties["icon-optional"] as? Bool } + set { impl.layerProperties["icon-optional"] = newValue } } /// Size of the additional area around the icon bounding box used for detecting symbol collisions. /// Default value: 2. Minimum value: 0. public var iconPadding: Double? { - get { - return layerProperties["icon-padding"] as? Double - } - set { - layerProperties["icon-padding"] = newValue - } + get { impl.layerProperties["icon-padding"] as? Double } + set { impl.layerProperties["icon-padding"] = newValue } } /// Orientation of icon when map is pitched. /// Default value: "auto". public var iconPitchAlignment: IconPitchAlignment? { - get { - return layerProperties["icon-pitch-alignment"].flatMap { $0 as? String }.flatMap(IconPitchAlignment.init(rawValue:)) - } - set { - layerProperties["icon-pitch-alignment"] = newValue?.rawValue - } + get { impl.layerProperties["icon-pitch-alignment"].flatMap { $0 as? String }.flatMap(IconPitchAlignment.init(rawValue:)) } + set { impl.layerProperties["icon-pitch-alignment"] = newValue?.rawValue } } /// In combination with `symbol-placement`, determines the rotation behavior of icons. /// Default value: "auto". public var iconRotationAlignment: IconRotationAlignment? { - get { - return layerProperties["icon-rotation-alignment"].flatMap { $0 as? String }.flatMap(IconRotationAlignment.init(rawValue:)) - } - set { - layerProperties["icon-rotation-alignment"] = newValue?.rawValue - } + get { impl.layerProperties["icon-rotation-alignment"].flatMap { $0 as? String }.flatMap(IconRotationAlignment.init(rawValue:)) } + set { impl.layerProperties["icon-rotation-alignment"] = newValue?.rawValue } } /// If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer. When using a client that supports global collision detection, like Mapbox GL JS version 0.42.0 or greater, enabling this property is not needed to prevent clipped labels at tile boundaries. /// Default value: false. public var symbolAvoidEdges: Bool? { - get { - return layerProperties["symbol-avoid-edges"] as? Bool - } - set { - layerProperties["symbol-avoid-edges"] = newValue - } + get { impl.layerProperties["symbol-avoid-edges"] as? Bool } + set { impl.layerProperties["symbol-avoid-edges"] = newValue } } /// Label placement relative to its geometry. /// Default value: "point". public var symbolPlacement: SymbolPlacement? { - get { - return layerProperties["symbol-placement"].flatMap { $0 as? String }.flatMap(SymbolPlacement.init(rawValue:)) - } - set { - layerProperties["symbol-placement"] = newValue?.rawValue - } + get { impl.layerProperties["symbol-placement"].flatMap { $0 as? String }.flatMap(SymbolPlacement.init(rawValue:)) } + set { impl.layerProperties["symbol-placement"] = newValue?.rawValue } } /// Distance between two symbol anchors. /// Default value: 250. Minimum value: 1. public var symbolSpacing: Double? { - get { - return layerProperties["symbol-spacing"] as? Double - } - set { - layerProperties["symbol-spacing"] = newValue - } + get { impl.layerProperties["symbol-spacing"] as? Double } + set { impl.layerProperties["symbol-spacing"] = newValue } } /// Position symbol on buildings (both fill extrusions and models) rooftops. In order to have minimal impact on performance, this is supported only when `fill-extrusion-height` is not zoom-dependent and remains unchanged. For fading in buildings when zooming in, fill-extrusion-vertical-scale should be used and symbols would raise with building rooftops. Symbols are sorted by elevation, except in cases when `viewport-y` sorting or `symbol-sort-key` are applied. /// Default value: false. public var symbolZElevate: Bool? { - get { - return layerProperties["symbol-z-elevate"] as? Bool - } - set { - layerProperties["symbol-z-elevate"] = newValue - } + get { impl.layerProperties["symbol-z-elevate"] as? Bool } + set { impl.layerProperties["symbol-z-elevate"] = newValue } } /// Determines whether overlapping symbols in the same layer are rendered in the order that they appear in the data source or by their y-position relative to the viewport. To control the order and prioritization of symbols otherwise, use `symbol-sort-key`. /// Default value: "auto". public var symbolZOrder: SymbolZOrder? { - get { - return layerProperties["symbol-z-order"].flatMap { $0 as? String }.flatMap(SymbolZOrder.init(rawValue:)) - } - set { - layerProperties["symbol-z-order"] = newValue?.rawValue - } + get { impl.layerProperties["symbol-z-order"].flatMap { $0 as? String }.flatMap(SymbolZOrder.init(rawValue:)) } + set { impl.layerProperties["symbol-z-order"] = newValue?.rawValue } } /// If true, the text will be visible even if it collides with other previously drawn symbols. /// Default value: false. public var textAllowOverlap: Bool? { - get { - return layerProperties["text-allow-overlap"] as? Bool - } - set { - layerProperties["text-allow-overlap"] = newValue - } + get { impl.layerProperties["text-allow-overlap"] as? Bool } + set { impl.layerProperties["text-allow-overlap"] = newValue } } /// Font stack to use for displaying text. public var textFont: [String]? { - get { - return (layerProperties["text-font"] as? [Any])?[1] as? [String] - } - set { - layerProperties["text-font"] = newValue.map { ["literal", $0] as [Any] } - } + get { (impl.layerProperties["text-font"] as? [Any])?[1] as? [String] } + set { impl.layerProperties["text-font"] = newValue.map { ["literal", $0] as [Any] } } } /// If true, other symbols can be visible even if they collide with the text. /// Default value: false. public var textIgnorePlacement: Bool? { - get { - return layerProperties["text-ignore-placement"] as? Bool - } - set { - layerProperties["text-ignore-placement"] = newValue - } + get { impl.layerProperties["text-ignore-placement"] as? Bool } + set { impl.layerProperties["text-ignore-placement"] = newValue } } /// If true, the text may be flipped vertically to prevent it from being rendered upside-down. /// Default value: true. public var textKeepUpright: Bool? { - get { - return layerProperties["text-keep-upright"] as? Bool - } - set { - layerProperties["text-keep-upright"] = newValue - } + get { impl.layerProperties["text-keep-upright"] as? Bool } + set { impl.layerProperties["text-keep-upright"] = newValue } } /// Maximum angle change between adjacent characters. /// Default value: 45. public var textMaxAngle: Double? { - get { - return layerProperties["text-max-angle"] as? Double - } - set { - layerProperties["text-max-angle"] = newValue - } + get { impl.layerProperties["text-max-angle"] as? Double } + set { impl.layerProperties["text-max-angle"] = newValue } } /// If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not. /// Default value: false. public var textOptional: Bool? { - get { - return layerProperties["text-optional"] as? Bool - } - set { - layerProperties["text-optional"] = newValue - } + get { impl.layerProperties["text-optional"] as? Bool } + set { impl.layerProperties["text-optional"] = newValue } } /// Size of the additional area around the text bounding box used for detecting symbol collisions. /// Default value: 2. Minimum value: 0. public var textPadding: Double? { - get { - return layerProperties["text-padding"] as? Double - } - set { - layerProperties["text-padding"] = newValue - } + get { impl.layerProperties["text-padding"] as? Double } + set { impl.layerProperties["text-padding"] = newValue } } /// Orientation of text when map is pitched. /// Default value: "auto". public var textPitchAlignment: TextPitchAlignment? { - get { - return layerProperties["text-pitch-alignment"].flatMap { $0 as? String }.flatMap(TextPitchAlignment.init(rawValue:)) - } - set { - layerProperties["text-pitch-alignment"] = newValue?.rawValue - } + get { impl.layerProperties["text-pitch-alignment"].flatMap { $0 as? String }.flatMap(TextPitchAlignment.init(rawValue:)) } + set { impl.layerProperties["text-pitch-alignment"] = newValue?.rawValue } } /// In combination with `symbol-placement`, determines the rotation behavior of the individual glyphs forming the text. /// Default value: "auto". public var textRotationAlignment: TextRotationAlignment? { - get { - return layerProperties["text-rotation-alignment"].flatMap { $0 as? String }.flatMap(TextRotationAlignment.init(rawValue:)) - } - set { - layerProperties["text-rotation-alignment"] = newValue?.rawValue - } + get { impl.layerProperties["text-rotation-alignment"].flatMap { $0 as? String }.flatMap(TextRotationAlignment.init(rawValue:)) } + set { impl.layerProperties["text-rotation-alignment"] = newValue?.rawValue } } /// To increase the chance of placing high-priority labels on the map, you can provide an array of `text-anchor` locations: the renderer will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the `text-radial-offset` or the two-dimensional `text-offset`. public var textVariableAnchor: [TextAnchor]? { - get { - return layerProperties["text-variable-anchor"].flatMap { $0 as? [String] }.flatMap { $0.compactMap(TextAnchor.init(rawValue:)) } - } - set { - layerProperties["text-variable-anchor"] = newValue?.map(\.rawValue) - } + get { impl.layerProperties["text-variable-anchor"].flatMap { $0 as? [String] }.flatMap { $0.compactMap(TextAnchor.init(rawValue:)) } } + set { impl.layerProperties["text-variable-anchor"] = newValue?.map(\.rawValue) } } /// The property allows control over a symbol's orientation. Note that the property values act as a hint, so that a symbol whose language doesn’t support the provided orientation will be laid out in its natural orientation. Example: English point symbol will be rendered horizontally even if array value contains single 'vertical' enum value. For symbol with point placement, the order of elements in an array define priority order for the placement of an orientation variant. For symbol with line placement, the default text writing mode is either ['horizontal', 'vertical'] or ['vertical', 'horizontal'], the order doesn't affect the placement. public var textWritingMode: [TextWritingMode]? { - get { - return layerProperties["text-writing-mode"].flatMap { $0 as? [String] }.flatMap { $0.compactMap(TextWritingMode.init(rawValue:)) } - } - set { - layerProperties["text-writing-mode"] = newValue?.map(\.rawValue) - } + get { impl.layerProperties["text-writing-mode"].flatMap { $0 as? [String] }.flatMap { $0.compactMap(TextWritingMode.init(rawValue:)) } } + set { impl.layerProperties["text-writing-mode"] = newValue?.map(\.rawValue) } } /// Increase or reduce the saturation of the symbol icon. /// Default value: 0. Value range: [-1, 1] public var iconColorSaturation: Double? { - get { - return layerProperties["icon-color-saturation"] as? Double - } - set { - layerProperties["icon-color-saturation"] = newValue - } + get { impl.layerProperties["icon-color-saturation"] as? Double } + set { impl.layerProperties["icon-color-saturation"] = newValue } } /// Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up. /// Default value: [0,0]. public var iconTranslate: [Double]? { - get { - return layerProperties["icon-translate"] as? [Double] - } - set { - layerProperties["icon-translate"] = newValue - } + get { impl.layerProperties["icon-translate"] as? [Double] } + set { impl.layerProperties["icon-translate"] = newValue } } /// Controls the frame of reference for `icon-translate`. /// Default value: "map". public var iconTranslateAnchor: IconTranslateAnchor? { - get { - return layerProperties["icon-translate-anchor"].flatMap { $0 as? String }.flatMap(IconTranslateAnchor.init(rawValue:)) - } - set { - layerProperties["icon-translate-anchor"] = newValue?.rawValue - } + get { impl.layerProperties["icon-translate-anchor"].flatMap { $0 as? String }.flatMap(IconTranslateAnchor.init(rawValue:)) } + set { impl.layerProperties["icon-translate-anchor"] = newValue?.rawValue } } /// Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up. /// Default value: [0,0]. public var textTranslate: [Double]? { - get { - return layerProperties["text-translate"] as? [Double] - } - set { - layerProperties["text-translate"] = newValue - } + get { impl.layerProperties["text-translate"] as? [Double] } + set { impl.layerProperties["text-translate"] = newValue } } /// Controls the frame of reference for `text-translate`. /// Default value: "map". public var textTranslateAnchor: TextTranslateAnchor? { - get { - return layerProperties["text-translate-anchor"].flatMap { $0 as? String }.flatMap(TextTranslateAnchor.init(rawValue:)) - } - set { - layerProperties["text-translate-anchor"] = newValue?.rawValue - } + get { impl.layerProperties["text-translate-anchor"].flatMap { $0 as? String }.flatMap(TextTranslateAnchor.init(rawValue:)) } + set { impl.layerProperties["text-translate-anchor"] = newValue?.rawValue } } /// Slot for the underlying layer. @@ -651,228 +284,37 @@ public class PointAnnotationManager: AnnotationManagerInternal { /// Use this property to position the annotations relative to other map features if you use Mapbox Standard Style. /// See for more info. public var slot: String? { - get { - return layerProperties["slot"] as? String - } - set { - layerProperties["slot"] = newValue - } + get { impl.layerProperties["slot"] as? String } + set { impl.layerProperties["slot"] = newValue } } /// Scales the icon to fit around the associated text. @available(*, deprecated, message: "icon-text-fit property is now data driven, use `PointAnnotation.iconTextFit` instead.") public var iconTextFit: IconTextFit? { - get { - return layerProperties["icon-text-fit"].flatMap { $0 as? String }.flatMap(IconTextFit.init(rawValue:)) - } - set { - layerProperties["icon-text-fit"] = newValue?.rawValue - } + get { impl.layerProperties["icon-text-fit"].flatMap { $0 as? String }.flatMap(IconTextFit.init(rawValue:)) } + set { impl.layerProperties["icon-text-fit"] = newValue?.rawValue } } /// Size of the additional area added to dimensions determined by `icon-text-fit`, in clockwise order: top, right, bottom, left. @available(*, deprecated, message: "icon-text-fit-padding property is now data driven, use `PointAnnotation.iconTextFitPadding` instead.") public var iconTextFitPadding: [Double]? { - get { - return layerProperties["icon-text-fit-padding"] as? [Double] - } - set { - layerProperties["icon-text-fit-padding"] = newValue - } + get {impl.layerProperties["icon-text-fit-padding"] as? [Double] } + set { impl.layerProperties["icon-text-fit-padding"] = newValue } } /// The opacity at which the icon will be drawn in case of being depth occluded. Absent value means full occlusion against terrain only. /// Default value: 0. Value range: [0, 1] @available(*, deprecated, message: "icon-occlusion-opacity property is now data driven, use `PointAnnotation.iconOcclusionOpacity` instead.") public var iconOcclusionOpacity: Double? { - get { - return layerProperties["icon-occlusion-opacity"] as? Double - } - set { - layerProperties["icon-occlusion-opacity"] = newValue - } + get { impl.layerProperties["icon-occlusion-opacity"] as? Double } + set { impl.layerProperties["icon-occlusion-opacity"] = newValue } } - /// The opacity at which the text will be drawn in case of being depth occluded. Absent value means full occlusion against terrain only. /// Default value: 0. Value range: [0, 1] @available(*, deprecated, message: "text-occlusion-opacity property is now data driven, use `PointAnnotation.textOcclusionOpacity` instead.") public var textOcclusionOpacity: Double? { - get { - return layerProperties["text-occlusion-opacity"] as? Double - } - set { - layerProperties["text-occlusion-opacity"] = newValue - } - } - - // MARK: - User interaction handling - - private var queryToken: AnyCancelable? - private func queryAnnotationClusterContext( - feature: Feature, - context: MapContentGestureContext, - completion: @escaping (Result) -> Void - ) { - queryToken = mapFeatureQueryable - .getAnnotationClusterContext(layerId: id, feature: feature, context: context, completion: completion) - .erased - } - - func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - if layerId == clusterId, let onClusterTap { - queryAnnotationClusterContext(feature: feature, context: context) { result in - if case let .success(clusterContext) = result { - onClusterTap(clusterContext) - } - } - return true - } - - guard let featureId = feature.identifier?.string else { return false } - - let tappedIndex = annotations.firstIndex { $0.id == featureId } - guard let tappedIndex else { return false } - var tappedAnnotation = annotations[tappedIndex] - - tappedAnnotation.isSelected.toggle() - - if !isSwiftUI { - // In-place update of annotations is not supported in SwiftUI. - // Use the .onTapGesture {} to update annotations on call side. - self.annotations[tappedIndex] = tappedAnnotation - } - - _delegate?.annotationManager( - self, - didDetectTappedAnnotations: [tappedAnnotation]) - - return tappedAnnotation.tapHandler?(context) ?? false - } - - func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - if layerId == clusterId, let onClusterLongPress { - queryAnnotationClusterContext(feature: feature, context: context) { result in - if case let .success(clusterContext) = result { - onClusterLongPress(clusterContext) - } - } - return true - } - guard let featureId = feature.identifier?.string else { return false } - - return annotations.first { $0.id == featureId }?.longPressHandler?(context) ?? false - } - - func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool { - guard !isSwiftUI else { return false } - - func predicate(annotation: PointAnnotation) -> Bool { - annotation.id == featureId && annotation.isDraggable - } - - func tryBeginDragging(_ annotations: inout [PointAnnotation], idx: Int) -> Bool { - var annotation = annotations[idx] - // If no drag handler set, the dragging is allowed - let dragAllowed = annotation.dragBeginHandler?(&annotation, context) ?? true - annotations[idx] = annotation - return dragAllowed - } - - /// First, try to drag annotations that are already on the dragging layer. - if let idx = draggedAnnotations.firstIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&draggedAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - draggedAnnotationIndex = idx - return true - } - - /// Then, try to start dragging from the main set of annotations. - if let idx = mainAnnotations.lastIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&mainAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - insertDraggedLayerAndSource() - - let annotation = mainAnnotations.remove(at: idx) - draggedAnnotations.append(annotation) - draggedAnnotationIndex = draggedAnnotations.endIndex - 1 - return true - } - - return false - } - - private func insertDraggedLayerAndSource() { - insertDraggedLayerAndSourceOnce { - let source = GeoJSONSource(id: dragId) - let layer = SymbolLayer(id: dragId, source: dragId) - do { - try style.addSource(source) - try style.addPersistentLayer(layer, layerPosition: .above(layerId)) - } catch { - Log.error(forMessage: "Add drag source/layer \(error)", category: "Annotations") - } - } - } - - func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) { - guard !isSwiftUI, - let draggedAnnotationIndex, - draggedAnnotationIndex < draggedAnnotations.endIndex, - let point = offsetCalculator.geometry(for: translation, from: draggedAnnotations[draggedAnnotationIndex].point) else { - return - } - - draggedAnnotations[draggedAnnotationIndex].point = point - - callDragHandler(\.dragChangeHandler, context: context) - } - - func handleDragEnd(context: MapContentGestureContext) { - guard !isSwiftUI else { return } - callDragHandler(\.dragEndHandler, context: context) - draggedAnnotationIndex = nil - } - - private func callDragHandler( - _ keyPath: KeyPath Void)?>, - context: MapContentGestureContext - ) { - guard let draggedAnnotationIndex, draggedAnnotationIndex < draggedAnnotations.endIndex else { - return - } - - if let handler = draggedAnnotations[draggedAnnotationIndex][keyPath: keyPath] { - var copy = draggedAnnotations[draggedAnnotationIndex] - handler(©, context) - draggedAnnotations[draggedAnnotationIndex] = copy - } - } -} - -private extension PointAnnotationManager { - - func addImages(_ images: Set) { - for image in images { - imagesManager.addImage(image.image, id: image.name, sdf: false, contentInsets: .zero) - } - } - - func removeImages(_ names: Set) { - for imageName in names { - imagesManager.removeImage(imageName) - } - } - - func removeAllImages() { - let imagesToRemove = allImages - allImages.removeAll() - removeImages(imagesToRemove) + get { impl.layerProperties["text-occlusion-opacity"] as? Double } + set { impl.layerProperties["text-occlusion-opacity"] = newValue } } } diff --git a/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotation.swift b/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotation.swift index c9c11e646d4a..393d4d694448 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotation.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotation.swift @@ -1,19 +1,24 @@ // This file is generated. import UIKit -public struct PolygonAnnotation: Annotation, Equatable { +public struct PolygonAnnotation: Annotation, Equatable, AnnotationInternal { /// Identifier for this annotation internal(set) public var id: String /// The geometry backing this annotation public var geometry: Geometry { - return .polygon(polygon) + .polygon(polygon) } - /// The polygon backing this annotation + /// The Polygon backing this annotation public var polygon: Polygon + var _geometry: Polygon { + get { polygon } + set { polygon = newValue } + } + /// Toggles the annotation's selection state. /// If the annotation is deselected, it becomes selected. /// If the annotation is selected, it becomes deselected. @@ -223,7 +228,7 @@ extension PolygonAnnotation { } @available(iOS 13.0, *) -extension PolygonAnnotation: MapContent, PrimitiveMapContent, MapContentAnnotation { +extension PolygonAnnotation: MapContent, PrimitiveMapContent { func visit(_ node: MapContentNode) { PolygonAnnotationGroup { self }.visit(node) } diff --git a/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotationManager.swift b/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotationManager.swift index b833192a47c8..a04c5846e0ac 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotationManager.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PolygonAnnotationManager.swift @@ -1,44 +1,25 @@ // This file is generated. -import Foundation -import os -@_implementationOnly import MapboxCommon_Private -/// An instance of `PolygonAnnotationManager` is responsible for a collection of `PolygonAnnotation`s. -public class PolygonAnnotationManager: AnnotationManagerInternal { - typealias OffsetCalculatorType = OffsetPolygonCalculator - - public var sourceId: String { id } - - public var layerId: String { id } - private var dragId: String { "\(id)_drag" } +/// An instance of `PolygonAnnotationManager` is responsible for a collection of `PolygonAnnotation`s. +public class PolygonAnnotationManager: AnnotationManager, AnnotationManagerInternal, AnnotationManagerImplDelegate { + typealias Impl = AnnotationManagerImpl - public let id: String + public var sourceId: String { impl.id } + public var layerId: String { impl.id } + public var id: String { impl.id } - var layerPosition: LayerPosition? { - didSet { - do { - try style.moveLayer(withId: layerId, to: layerPosition ?? .default) - } catch { - Log.error(forMessage: "Failed to mover layer to a new position. Error: \(error)", category: "Annotations") - } - } - } + let impl: AnnotationManagerImpl /// The collection of ``PolygonAnnotation`` being managed. /// /// Each annotation must have a unique identifier. Duplicate IDs will cause only the first annotation to be displayed, while the rest will be ignored. public var annotations: [PolygonAnnotation] { - get { mainAnnotations + draggedAnnotations } - set { - mainAnnotations = newValue - mainAnnotations.removeDuplicates() - draggedAnnotations.removeAll(keepingCapacity: true) - draggedAnnotationIndex = nil - } + get { impl.annotations } + set { impl.annotations = newValue } } /// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager. - /// - NOTE: This annotation manager listens to tap events via the `GestureManager.singleTapGestureRecognizer`. + /// - NOTE: This annotation manager listens to tap events via the ``GestureManager/singleTapGestureRecognizer``. @available(*, deprecated, message: "Use tapHandler property of Annotation") public weak var delegate: AnnotationInteractionDelegate? { get { _delegate } @@ -46,242 +27,46 @@ public class PolygonAnnotationManager: AnnotationManagerInternal { } private weak var _delegate: AnnotationInteractionDelegate? - // Deps - private let style: StyleProtocol - private let offsetCalculator: OffsetCalculatorType - - // Private state - - /// Currently displayed (synced) annotations. - private var displayedAnnotations: [PolygonAnnotation] = [] - - /// Updated, non-moved annotations. On next display link they will be diffed with `displayedAnnotations` and updated. - private var mainAnnotations = [PolygonAnnotation]() { - didSet { syncSourceOnce.reset() } - } - - /// When annotation is moved for the first time, it migrates to this array from mainAnnotations. - private var draggedAnnotations = [PolygonAnnotation]() { - didSet { - if insertDraggedLayerAndSourceOnce.happened { - // Update dragged annotation only when the drag layer is created. - syncDragSourceOnce.reset() - } - } + required init(params: AnnotationManagerParams, deps: AnnotationManagerDeps) { + self.impl = .init(params: params, deps: deps) + impl.delegate = self } - /// Storage for common layer properties - var layerProperties: [String: Any] = [:] { - didSet { - syncLayerOnce.reset() - } - } - - /// The keys of the style properties that were set during the previous sync. - /// Used to identify which styles need to be restored to their default values in - /// the subsequent sync. - private var previouslySetLayerPropertyKeys: Set = [] - - private var draggedAnnotationIndex: Array.Index? - private var destroyOnce = Once() - private var syncSourceOnce = Once(happened: true) - private var syncDragSourceOnce = Once(happened: true) - private var syncLayerOnce = Once(happened: true) - private var insertDraggedLayerAndSourceOnce = Once() - private var displayLinkToken: AnyCancelable? - - var allLayerIds: [String] { [layerId, dragId] } - - /// In SwiftUI isDraggable and isSelected are disabled. - var isSwiftUI = false - - init(id: String, - style: StyleProtocol, - layerPosition: LayerPosition?, - displayLink: Signal, - offsetCalculator: OffsetCalculatorType - ) { - self.id = id - self.style = style - self.offsetCalculator = offsetCalculator - - do { - // Add the source with empty `data` property - let source = GeoJSONSource(id: sourceId) - try style.addSource(source) - - // Add the correct backing layer for this annotation type - let layer = FillLayer(id: layerId, source: sourceId) - try style.addPersistentLayer(layer, layerPosition: layerPosition) - } catch { - Log.error( - forMessage: "Failed to create source / layer in PolygonAnnotationManager. Error: \(error)", - category: "Annotations") - } - - displayLinkToken = displayLink.observe { [weak self] in - self?.syncSourceAndLayerIfNeeded() - } - } - - var idsMap = [AnyHashable: String]() - - func set(newAnnotations: [(AnyHashable, PolygonAnnotation)]) { - var resolvedAnnotations = [PolygonAnnotation]() - newAnnotations.forEach { elementId, annotation in - var annotation = annotation - let stringId = idsMap[elementId] ?? annotation.id - idsMap[elementId] = stringId - annotation.id = stringId - annotation.isDraggable = false - annotation.isSelected = false - resolvedAnnotations.append(annotation) - } - annotations = resolvedAnnotations - } - - func destroy() { - guard destroyOnce.continueOnce() else { return } - - displayLinkToken?.cancel() - - func wrapError(_ what: String, _ body: () throws -> Void) { - do { - try body() - } catch { - Log.warning( - forMessage: "Failed to remove \(what) for PolygonAnnotationManager with id \(id) due to error: \(error)", - category: "Annotations") - } - } - - wrapError("layer") { - try style.removeLayer(withId: layerId) - } - - wrapError("source") { - try style.removeSource(withId: sourceId) - } - - if insertDraggedLayerAndSourceOnce.happened { - wrapError("drag source and layer") { - try style.removeLayer(withId: dragId) - try style.removeSource(withId: dragId) - } - } - } - - // MARK: - Sync annotations to map - - private func syncSource() { - guard syncSourceOnce.continueOnce() else { return } - - let diff = mainAnnotations.diff(from: displayedAnnotations, id: \.id) - syncLayerOnce.reset(if: !diff.isEmpty) - style.apply(annotationsDiff: diff, sourceId: sourceId, feature: \.feature) - displayedAnnotations = mainAnnotations - } - - private func syncDragSource() { - guard syncDragSourceOnce.continueOnce() else { return } - - let fc = FeatureCollection(features: draggedAnnotations.map(\.feature)) - style.updateGeoJSONSource(withId: dragId, geoJSON: .featureCollection(fc)) - } - - private func syncLayer() { - guard syncLayerOnce.continueOnce() else { return } - - // Construct the properties dictionary from the annotations - let dataDrivenLayerPropertyKeys = Set(annotations.flatMap(\.layerProperties.keys)) - let dataDrivenProperties = Dictionary( - uniqueKeysWithValues: dataDrivenLayerPropertyKeys - .map { (key) -> (String, Any) in - (key, ["get", key, ["get", "layerProperties"]] as [Any]) - }) - - // Merge the common layer properties - let newLayerProperties = dataDrivenProperties.merging(layerProperties, uniquingKeysWith: { $1 }) - - // Construct the properties dictionary to reset any properties that are no longer used - let unusedPropertyKeys = previouslySetLayerPropertyKeys.subtracting(newLayerProperties.keys) - let unusedProperties = Dictionary(uniqueKeysWithValues: unusedPropertyKeys.map { (key) -> (String, Any) in - (key, StyleManager.layerPropertyDefaultValue(for: .fill, property: key).value) - }) - - // Store the new set of property keys - previouslySetLayerPropertyKeys = Set(newLayerProperties.keys) - - // Merge the new and unused properties - let allLayerProperties = newLayerProperties.merging(unusedProperties, uniquingKeysWith: { $1 }) - - // make a single call into MapboxCoreMaps to set layer properties - do { - try style.setLayerProperties(for: layerId, properties: allLayerProperties) - if !draggedAnnotations.isEmpty { - try style.setLayerProperties(for: dragId, properties: allLayerProperties) - } - } catch { - Log.error( - forMessage: "Could not set layer properties in PolygonAnnotationManager due to error \(error)", - category: "Annotations") - } + func didTap(_ annotations: [Annotation]) { + _delegate?.annotationManager(self, didDetectTappedAnnotations: annotations) } - func syncSourceAndLayerIfNeeded() { - guard !destroyOnce.happened else { return } - - OSLog.platform.withIntervalSignpost(SignpostName.mapViewDisplayLink, "Participant: PolygonAnnotationManager") { - syncSource() - syncDragSource() - syncLayer() - } - } + func syncImages() {} + func removeAllImages() {} // MARK: - Common layer properties /// Whether or not the fill should be antialiased. /// Default value: true. public var fillAntialias: Bool? { - get { - return layerProperties["fill-antialias"] as? Bool - } - set { - layerProperties["fill-antialias"] = newValue - } + get { impl.layerProperties["fill-antialias"] as? Bool } + set { impl.layerProperties["fill-antialias"] = newValue } } /// Controls the intensity of light emitted on the source features. /// Default value: 0. Minimum value: 0. public var fillEmissiveStrength: Double? { - get { - return layerProperties["fill-emissive-strength"] as? Double - } - set { - layerProperties["fill-emissive-strength"] = newValue - } + get { impl.layerProperties["fill-emissive-strength"] as? Double } + set { impl.layerProperties["fill-emissive-strength"] = newValue } } /// The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively. /// Default value: [0,0]. public var fillTranslate: [Double]? { - get { - return layerProperties["fill-translate"] as? [Double] - } - set { - layerProperties["fill-translate"] = newValue - } + get { impl.layerProperties["fill-translate"] as? [Double] } + set { impl.layerProperties["fill-translate"] = newValue } } /// Controls the frame of reference for `fill-translate`. /// Default value: "map". public var fillTranslateAnchor: FillTranslateAnchor? { - get { - return layerProperties["fill-translate-anchor"].flatMap { $0 as? String }.flatMap(FillTranslateAnchor.init(rawValue:)) - } - set { - layerProperties["fill-translate-anchor"] = newValue?.rawValue - } + get { impl.layerProperties["fill-translate-anchor"].flatMap { $0 as? String }.flatMap(FillTranslateAnchor.init(rawValue:)) } + set { impl.layerProperties["fill-translate-anchor"] = newValue?.rawValue } } /// Slot for the underlying layer. @@ -289,135 +74,10 @@ public class PolygonAnnotationManager: AnnotationManagerInternal { /// Use this property to position the annotations relative to other map features if you use Mapbox Standard Style. /// See for more info. public var slot: String? { - get { - return layerProperties["slot"] as? String - } - set { - layerProperties["slot"] = newValue - } - } - - // MARK: - User interaction handling - - func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - - guard let featureId = feature.identifier?.string else { return false } - - let tappedIndex = annotations.firstIndex { $0.id == featureId } - guard let tappedIndex else { return false } - var tappedAnnotation = annotations[tappedIndex] - - tappedAnnotation.isSelected.toggle() - - if !isSwiftUI { - // In-place update of annotations is not supported in SwiftUI. - // Use the .onTapGesture {} to update annotations on call side. - self.annotations[tappedIndex] = tappedAnnotation - } - - _delegate?.annotationManager( - self, - didDetectTappedAnnotations: [tappedAnnotation]) - - return tappedAnnotation.tapHandler?(context) ?? false + get { impl.layerProperties["slot"] as? String } + set { impl.layerProperties["slot"] = newValue } } - func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - guard let featureId = feature.identifier?.string else { return false } - - return annotations.first { $0.id == featureId }?.longPressHandler?(context) ?? false - } - - func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool { - guard !isSwiftUI else { return false } - - func predicate(annotation: PolygonAnnotation) -> Bool { - annotation.id == featureId && annotation.isDraggable - } - - func tryBeginDragging(_ annotations: inout [PolygonAnnotation], idx: Int) -> Bool { - var annotation = annotations[idx] - // If no drag handler set, the dragging is allowed - let dragAllowed = annotation.dragBeginHandler?(&annotation, context) ?? true - annotations[idx] = annotation - return dragAllowed - } - - /// First, try to drag annotations that are already on the dragging layer. - if let idx = draggedAnnotations.firstIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&draggedAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - draggedAnnotationIndex = idx - return true - } - - /// Then, try to start dragging from the main set of annotations. - if let idx = mainAnnotations.lastIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&mainAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - insertDraggedLayerAndSource() - - let annotation = mainAnnotations.remove(at: idx) - draggedAnnotations.append(annotation) - draggedAnnotationIndex = draggedAnnotations.endIndex - 1 - return true - } - - return false - } - - private func insertDraggedLayerAndSource() { - insertDraggedLayerAndSourceOnce { - let source = GeoJSONSource(id: dragId) - let layer = FillLayer(id: dragId, source: dragId) - do { - try style.addSource(source) - try style.addPersistentLayer(layer, layerPosition: .above(layerId)) - } catch { - Log.error(forMessage: "Add drag source/layer \(error)", category: "Annotations") - } - } - } - - func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) { - guard !isSwiftUI, - let draggedAnnotationIndex, - draggedAnnotationIndex < draggedAnnotations.endIndex, - let polygon = offsetCalculator.geometry(for: translation, from: draggedAnnotations[draggedAnnotationIndex].polygon) else { - return - } - - draggedAnnotations[draggedAnnotationIndex].polygon = polygon - - callDragHandler(\.dragChangeHandler, context: context) - } - - func handleDragEnd(context: MapContentGestureContext) { - guard !isSwiftUI else { return } - callDragHandler(\.dragEndHandler, context: context) - draggedAnnotationIndex = nil - } - - private func callDragHandler( - _ keyPath: KeyPath Void)?>, - context: MapContentGestureContext - ) { - guard let draggedAnnotationIndex, draggedAnnotationIndex < draggedAnnotations.endIndex else { - return - } - - if let handler = draggedAnnotations[draggedAnnotationIndex][keyPath: keyPath] { - var copy = draggedAnnotations[draggedAnnotationIndex] - handler(©, context) - draggedAnnotations[draggedAnnotationIndex] = copy - } - } } // End of generated file. diff --git a/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotation.swift b/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotation.swift index 5c071c0d602c..6cc7ace90587 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotation.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotation.swift @@ -1,19 +1,24 @@ // This file is generated. import UIKit -public struct PolylineAnnotation: Annotation, Equatable { +public struct PolylineAnnotation: Annotation, Equatable, AnnotationInternal { /// Identifier for this annotation internal(set) public var id: String /// The geometry backing this annotation public var geometry: Geometry { - return .lineString(lineString) + .lineString(lineString) } - /// The line string backing this annotation + /// The LineString backing this annotation public var lineString: LineString + var _geometry: LineString { + get { lineString } + set { lineString = newValue } + } + /// Toggles the annotation's selection state. /// If the annotation is deselected, it becomes selected. /// If the annotation is selected, it becomes deselected. @@ -307,7 +312,7 @@ extension PolylineAnnotation { } @available(iOS 13.0, *) -extension PolylineAnnotation: MapContent, PrimitiveMapContent, MapContentAnnotation { +extension PolylineAnnotation: MapContent, PrimitiveMapContent { func visit(_ node: MapContentNode) { PolylineAnnotationGroup { self }.visit(node) } diff --git a/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotationManager.swift b/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotationManager.swift index 899c81ca3b5b..aff5e24a8ade 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotationManager.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PolylineAnnotationManager.swift @@ -1,44 +1,25 @@ // This file is generated. -import Foundation -import os -@_implementationOnly import MapboxCommon_Private -/// An instance of `PolylineAnnotationManager` is responsible for a collection of `PolylineAnnotation`s. -public class PolylineAnnotationManager: AnnotationManagerInternal { - typealias OffsetCalculatorType = OffsetLineStringCalculator - - public var sourceId: String { id } - - public var layerId: String { id } - private var dragId: String { "\(id)_drag" } +/// An instance of `PolylineAnnotationManager` is responsible for a collection of `PolylineAnnotation`s. +public class PolylineAnnotationManager: AnnotationManager, AnnotationManagerInternal, AnnotationManagerImplDelegate { + typealias Impl = AnnotationManagerImpl - public let id: String + public var sourceId: String { impl.id } + public var layerId: String { impl.id } + public var id: String { impl.id } - var layerPosition: LayerPosition? { - didSet { - do { - try style.moveLayer(withId: layerId, to: layerPosition ?? .default) - } catch { - Log.error(forMessage: "Failed to mover layer to a new position. Error: \(error)", category: "Annotations") - } - } - } + let impl: AnnotationManagerImpl /// The collection of ``PolylineAnnotation`` being managed. /// /// Each annotation must have a unique identifier. Duplicate IDs will cause only the first annotation to be displayed, while the rest will be ignored. public var annotations: [PolylineAnnotation] { - get { mainAnnotations + draggedAnnotations } - set { - mainAnnotations = newValue - mainAnnotations.removeDuplicates() - draggedAnnotations.removeAll(keepingCapacity: true) - draggedAnnotationIndex = nil - } + get { impl.annotations } + set { impl.annotations = newValue } } /// Set this delegate in order to be called back if a tap occurs on an annotation being managed by this manager. - /// - NOTE: This annotation manager listens to tap events via the `GestureManager.singleTapGestureRecognizer`. + /// - NOTE: This annotation manager listens to tap events via the ``GestureManager/singleTapGestureRecognizer``. @available(*, deprecated, message: "Use tapHandler property of Annotation") public weak var delegate: AnnotationInteractionDelegate? { get { _delegate } @@ -46,334 +27,102 @@ public class PolylineAnnotationManager: AnnotationManagerInternal { } private weak var _delegate: AnnotationInteractionDelegate? - // Deps - private let style: StyleProtocol - private let offsetCalculator: OffsetCalculatorType - - // Private state - - /// Currently displayed (synced) annotations. - private var displayedAnnotations: [PolylineAnnotation] = [] - - /// Updated, non-moved annotations. On next display link they will be diffed with `displayedAnnotations` and updated. - private var mainAnnotations = [PolylineAnnotation]() { - didSet { syncSourceOnce.reset() } - } - - /// When annotation is moved for the first time, it migrates to this array from mainAnnotations. - private var draggedAnnotations = [PolylineAnnotation]() { - didSet { - if insertDraggedLayerAndSourceOnce.happened { - // Update dragged annotation only when the drag layer is created. - syncDragSourceOnce.reset() - } - } + required init(params: AnnotationManagerParams, deps: AnnotationManagerDeps) { + self.impl = .init(params: params, deps: deps) + impl.delegate = self } - /// Storage for common layer properties - var layerProperties: [String: Any] = [:] { - didSet { - syncLayerOnce.reset() - } - } - - /// The keys of the style properties that were set during the previous sync. - /// Used to identify which styles need to be restored to their default values in - /// the subsequent sync. - private var previouslySetLayerPropertyKeys: Set = [] - - private var draggedAnnotationIndex: Array.Index? - private var destroyOnce = Once() - private var syncSourceOnce = Once(happened: true) - private var syncDragSourceOnce = Once(happened: true) - private var syncLayerOnce = Once(happened: true) - private var insertDraggedLayerAndSourceOnce = Once() - private var displayLinkToken: AnyCancelable? - - var allLayerIds: [String] { [layerId, dragId] } - - /// In SwiftUI isDraggable and isSelected are disabled. - var isSwiftUI = false - - init(id: String, - style: StyleProtocol, - layerPosition: LayerPosition?, - displayLink: Signal, - offsetCalculator: OffsetCalculatorType - ) { - self.id = id - self.style = style - self.offsetCalculator = offsetCalculator - - do { - // Add the source with empty `data` property - let source = GeoJSONSource(id: sourceId) - try style.addSource(source) - - // Add the correct backing layer for this annotation type - let layer = LineLayer(id: layerId, source: sourceId) - try style.addPersistentLayer(layer, layerPosition: layerPosition) - } catch { - Log.error( - forMessage: "Failed to create source / layer in PolylineAnnotationManager. Error: \(error)", - category: "Annotations") - } - - displayLinkToken = displayLink.observe { [weak self] in - self?.syncSourceAndLayerIfNeeded() - } - } - - var idsMap = [AnyHashable: String]() - - func set(newAnnotations: [(AnyHashable, PolylineAnnotation)]) { - var resolvedAnnotations = [PolylineAnnotation]() - newAnnotations.forEach { elementId, annotation in - var annotation = annotation - let stringId = idsMap[elementId] ?? annotation.id - idsMap[elementId] = stringId - annotation.id = stringId - annotation.isDraggable = false - annotation.isSelected = false - resolvedAnnotations.append(annotation) - } - annotations = resolvedAnnotations - } - - func destroy() { - guard destroyOnce.continueOnce() else { return } - - displayLinkToken?.cancel() - - func wrapError(_ what: String, _ body: () throws -> Void) { - do { - try body() - } catch { - Log.warning( - forMessage: "Failed to remove \(what) for PolylineAnnotationManager with id \(id) due to error: \(error)", - category: "Annotations") - } - } - - wrapError("layer") { - try style.removeLayer(withId: layerId) - } - - wrapError("source") { - try style.removeSource(withId: sourceId) - } - - if insertDraggedLayerAndSourceOnce.happened { - wrapError("drag source and layer") { - try style.removeLayer(withId: dragId) - try style.removeSource(withId: dragId) - } - } - } - - // MARK: - Sync annotations to map - - private func syncSource() { - guard syncSourceOnce.continueOnce() else { return } - - let diff = mainAnnotations.diff(from: displayedAnnotations, id: \.id) - syncLayerOnce.reset(if: !diff.isEmpty) - style.apply(annotationsDiff: diff, sourceId: sourceId, feature: \.feature) - displayedAnnotations = mainAnnotations - } - - private func syncDragSource() { - guard syncDragSourceOnce.continueOnce() else { return } - - let fc = FeatureCollection(features: draggedAnnotations.map(\.feature)) - style.updateGeoJSONSource(withId: dragId, geoJSON: .featureCollection(fc)) - } - - private func syncLayer() { - guard syncLayerOnce.continueOnce() else { return } - - // Construct the properties dictionary from the annotations - let dataDrivenLayerPropertyKeys = Set(annotations.flatMap(\.layerProperties.keys)) - let dataDrivenProperties = Dictionary( - uniqueKeysWithValues: dataDrivenLayerPropertyKeys - .map { (key) -> (String, Any) in - (key, ["get", key, ["get", "layerProperties"]] as [Any]) - }) - - // Merge the common layer properties - let newLayerProperties = dataDrivenProperties.merging(layerProperties, uniquingKeysWith: { $1 }) - - // Construct the properties dictionary to reset any properties that are no longer used - let unusedPropertyKeys = previouslySetLayerPropertyKeys.subtracting(newLayerProperties.keys) - let unusedProperties = Dictionary(uniqueKeysWithValues: unusedPropertyKeys.map { (key) -> (String, Any) in - (key, StyleManager.layerPropertyDefaultValue(for: .line, property: key).value) - }) - - // Store the new set of property keys - previouslySetLayerPropertyKeys = Set(newLayerProperties.keys) - - // Merge the new and unused properties - let allLayerProperties = newLayerProperties.merging(unusedProperties, uniquingKeysWith: { $1 }) - - // make a single call into MapboxCoreMaps to set layer properties - do { - try style.setLayerProperties(for: layerId, properties: allLayerProperties) - if !draggedAnnotations.isEmpty { - try style.setLayerProperties(for: dragId, properties: allLayerProperties) - } - } catch { - Log.error( - forMessage: "Could not set layer properties in PolylineAnnotationManager due to error \(error)", - category: "Annotations") - } + func didTap(_ annotations: [Annotation]) { + _delegate?.annotationManager(self, didDetectTappedAnnotations: annotations) } - func syncSourceAndLayerIfNeeded() { - guard !destroyOnce.happened else { return } - - OSLog.platform.withIntervalSignpost(SignpostName.mapViewDisplayLink, "Participant: PolylineAnnotationManager") { - syncSource() - syncDragSource() - syncLayer() - } - } + func syncImages() {} + func removeAllImages() {} // MARK: - Common layer properties /// The display of line endings. /// Default value: "butt". public var lineCap: LineCap? { - get { - return layerProperties["line-cap"].flatMap { $0 as? String }.flatMap(LineCap.init(rawValue:)) - } - set { - layerProperties["line-cap"] = newValue?.rawValue - } + get { impl.layerProperties["line-cap"].flatMap { $0 as? String }.flatMap(LineCap.init(rawValue:)) } + set { impl.layerProperties["line-cap"] = newValue?.rawValue } } /// Used to automatically convert miter joins to bevel joins for sharp angles. /// Default value: 2. public var lineMiterLimit: Double? { - get { - return layerProperties["line-miter-limit"] as? Double - } - set { - layerProperties["line-miter-limit"] = newValue - } + get { impl.layerProperties["line-miter-limit"] as? Double } + set { impl.layerProperties["line-miter-limit"] = newValue } } /// Used to automatically convert round joins to miter joins for shallow angles. /// Default value: 1.05. public var lineRoundLimit: Double? { - get { - return layerProperties["line-round-limit"] as? Double - } - set { - layerProperties["line-round-limit"] = newValue - } + get { impl.layerProperties["line-round-limit"] as? Double } + set { impl.layerProperties["line-round-limit"] = newValue } } /// Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels. /// Minimum value: 0. public var lineDasharray: [Double]? { - get { - return layerProperties["line-dasharray"] as? [Double] - } - set { - layerProperties["line-dasharray"] = newValue - } + get { impl.layerProperties["line-dasharray"] as? [Double] } + set { impl.layerProperties["line-dasharray"] = newValue } } /// Decrease line layer opacity based on occlusion from 3D objects. Value 0 disables occlusion, value 1 means fully occluded. /// Default value: 1. Value range: [0, 1] public var lineDepthOcclusionFactor: Double? { - get { - return layerProperties["line-depth-occlusion-factor"] as? Double - } - set { - layerProperties["line-depth-occlusion-factor"] = newValue - } + get { impl.layerProperties["line-depth-occlusion-factor"] as? Double } + set { impl.layerProperties["line-depth-occlusion-factor"] = newValue } } /// Controls the intensity of light emitted on the source features. /// Default value: 0. Minimum value: 0. public var lineEmissiveStrength: Double? { - get { - return layerProperties["line-emissive-strength"] as? Double - } - set { - layerProperties["line-emissive-strength"] = newValue - } + get { impl.layerProperties["line-emissive-strength"] as? Double } + set { impl.layerProperties["line-emissive-strength"] = newValue } } /// Opacity multiplier (multiplies line-opacity value) of the line part that is occluded by 3D objects. Value 0 hides occluded part, value 1 means the same opacity as non-occluded part. The property is not supported when `line-opacity` has data-driven styling. /// Default value: 0. Value range: [0, 1] public var lineOcclusionOpacity: Double? { - get { - return layerProperties["line-occlusion-opacity"] as? Double - } - set { - layerProperties["line-occlusion-opacity"] = newValue - } + get { impl.layerProperties["line-occlusion-opacity"] as? Double } + set { impl.layerProperties["line-occlusion-opacity"] = newValue } } /// The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively. /// Default value: [0,0]. public var lineTranslate: [Double]? { - get { - return layerProperties["line-translate"] as? [Double] - } - set { - layerProperties["line-translate"] = newValue - } + get { impl.layerProperties["line-translate"] as? [Double] } + set { impl.layerProperties["line-translate"] = newValue } } /// Controls the frame of reference for `line-translate`. /// Default value: "map". public var lineTranslateAnchor: LineTranslateAnchor? { - get { - return layerProperties["line-translate-anchor"].flatMap { $0 as? String }.flatMap(LineTranslateAnchor.init(rawValue:)) - } - set { - layerProperties["line-translate-anchor"] = newValue?.rawValue - } + get { impl.layerProperties["line-translate-anchor"].flatMap { $0 as? String }.flatMap(LineTranslateAnchor.init(rawValue:)) } + set { impl.layerProperties["line-translate-anchor"] = newValue?.rawValue } } /// The color to be used for rendering the trimmed line section that is defined by the `line-trim-offset` property. /// Default value: "transparent". - @_documentation(visibility: public) - @_spi(Experimental) public var lineTrimColor: StyleColor? { - get { - return layerProperties["line-trim-color"].flatMap { $0 as? String }.flatMap(StyleColor.init(rawValue:)) - } - set { - layerProperties["line-trim-color"] = newValue?.rawValue - } + get { impl.layerProperties["line-trim-color"].flatMap { $0 as? String }.flatMap(StyleColor.init(rawValue:)) } + set { impl.layerProperties["line-trim-color"] = newValue?.rawValue } } /// The fade range for the trim-start and trim-end points is defined by the `line-trim-offset` property. The first element of the array represents the fade range from the trim-start point toward the end of the line, while the second element defines the fade range from the trim-end point toward the beginning of the line. The fade result is achieved by interpolating between `line-trim-color` and the color specified by the `line-color` or the `line-gradient` property. /// Default value: [0,0]. Minimum value: [0,0]. Maximum value: [1,1]. - @_documentation(visibility: public) - @_spi(Experimental) public var lineTrimFadeRange: [Double]? { - get { - return layerProperties["line-trim-fade-range"] as? [Double] - } - set { - layerProperties["line-trim-fade-range"] = newValue - } + get { impl.layerProperties["line-trim-fade-range"] as? [Double] } + set { impl.layerProperties["line-trim-fade-range"] = newValue } } /// The line part between [trim-start, trim-end] will be painted using `line-trim-color,` which is transparent by default to produce a route vanishing effect. The line trim-off offset is based on the whole line range [0.0, 1.0]. /// Default value: [0,0]. Minimum value: [0,0]. Maximum value: [1,1]. public var lineTrimOffset: [Double]? { - get { - return layerProperties["line-trim-offset"] as? [Double] - } - set { - layerProperties["line-trim-offset"] = newValue - } + get { impl.layerProperties["line-trim-offset"] as? [Double] } + set { impl.layerProperties["line-trim-offset"] = newValue } } /// Slot for the underlying layer. @@ -381,135 +130,10 @@ public class PolylineAnnotationManager: AnnotationManagerInternal { /// Use this property to position the annotations relative to other map features if you use Mapbox Standard Style. /// See for more info. public var slot: String? { - get { - return layerProperties["slot"] as? String - } - set { - layerProperties["slot"] = newValue - } - } - - // MARK: - User interaction handling - - func handleTap(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - - guard let featureId = feature.identifier?.string else { return false } - - let tappedIndex = annotations.firstIndex { $0.id == featureId } - guard let tappedIndex else { return false } - var tappedAnnotation = annotations[tappedIndex] - - tappedAnnotation.isSelected.toggle() - - if !isSwiftUI { - // In-place update of annotations is not supported in SwiftUI. - // Use the .onTapGesture {} to update annotations on call side. - self.annotations[tappedIndex] = tappedAnnotation - } - - _delegate?.annotationManager( - self, - didDetectTappedAnnotations: [tappedAnnotation]) - - return tappedAnnotation.tapHandler?(context) ?? false + get { impl.layerProperties["slot"] as? String } + set { impl.layerProperties["slot"] = newValue } } - func handleLongPress(layerId: String, feature: Feature, context: MapContentGestureContext) -> Bool { - guard let featureId = feature.identifier?.string else { return false } - - return annotations.first { $0.id == featureId }?.longPressHandler?(context) ?? false - } - - func handleDragBegin(with featureId: String, context: MapContentGestureContext) -> Bool { - guard !isSwiftUI else { return false } - - func predicate(annotation: PolylineAnnotation) -> Bool { - annotation.id == featureId && annotation.isDraggable - } - - func tryBeginDragging(_ annotations: inout [PolylineAnnotation], idx: Int) -> Bool { - var annotation = annotations[idx] - // If no drag handler set, the dragging is allowed - let dragAllowed = annotation.dragBeginHandler?(&annotation, context) ?? true - annotations[idx] = annotation - return dragAllowed - } - - /// First, try to drag annotations that are already on the dragging layer. - if let idx = draggedAnnotations.firstIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&draggedAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - draggedAnnotationIndex = idx - return true - } - - /// Then, try to start dragging from the main set of annotations. - if let idx = mainAnnotations.lastIndex(where: predicate) { - let dragAllowed = tryBeginDragging(&mainAnnotations, idx: idx) - guard dragAllowed else { - return false - } - - insertDraggedLayerAndSource() - - let annotation = mainAnnotations.remove(at: idx) - draggedAnnotations.append(annotation) - draggedAnnotationIndex = draggedAnnotations.endIndex - 1 - return true - } - - return false - } - - private func insertDraggedLayerAndSource() { - insertDraggedLayerAndSourceOnce { - let source = GeoJSONSource(id: dragId) - let layer = LineLayer(id: dragId, source: dragId) - do { - try style.addSource(source) - try style.addPersistentLayer(layer, layerPosition: .above(layerId)) - } catch { - Log.error(forMessage: "Add drag source/layer \(error)", category: "Annotations") - } - } - } - - func handleDragChange(with translation: CGPoint, context: MapContentGestureContext) { - guard !isSwiftUI, - let draggedAnnotationIndex, - draggedAnnotationIndex < draggedAnnotations.endIndex, - let lineString = offsetCalculator.geometry(for: translation, from: draggedAnnotations[draggedAnnotationIndex].lineString) else { - return - } - - draggedAnnotations[draggedAnnotationIndex].lineString = lineString - - callDragHandler(\.dragChangeHandler, context: context) - } - - func handleDragEnd(context: MapContentGestureContext) { - guard !isSwiftUI else { return } - callDragHandler(\.dragEndHandler, context: context) - draggedAnnotationIndex = nil - } - - private func callDragHandler( - _ keyPath: KeyPath Void)?>, - context: MapContentGestureContext - ) { - guard let draggedAnnotationIndex, draggedAnnotationIndex < draggedAnnotations.endIndex else { - return - } - - if let handler = draggedAnnotations[draggedAnnotationIndex][keyPath: keyPath] { - var copy = draggedAnnotations[draggedAnnotationIndex] - handler(©, context) - draggedAnnotations[draggedAnnotationIndex] = copy - } - } } // End of generated file. diff --git a/Sources/MapboxMaps/Annotations/OffsetGeometryCalculator.swift b/Sources/MapboxMaps/Annotations/OffsetGeometryCalculator.swift index 97d70b01d988..f8cc4c6cf5b3 100644 --- a/Sources/MapboxMaps/Annotations/OffsetGeometryCalculator.swift +++ b/Sources/MapboxMaps/Annotations/OffsetGeometryCalculator.swift @@ -1,9 +1,10 @@ import UIKit @_implementationOnly import MapboxCommon_Private -internal protocol OffsetGeometryCalculator { +protocol OffsetGeometryCalculator { associatedtype GeometryType: GeometryConvertible func geometry(for translation: CGPoint, from geometry: GeometryType) -> GeometryType? + init(mapboxMap: MapboxMapProtocol) } internal struct OffsetPointCalculator: OffsetGeometryCalculator { diff --git a/Sources/MapboxMaps/ContentBuilders/MapContent/MapContentAnnotation.swift b/Sources/MapboxMaps/ContentBuilders/MapContent/MapContentAnnotation.swift deleted file mode 100644 index a7157f0cb239..000000000000 --- a/Sources/MapboxMaps/ContentBuilders/MapContent/MapContentAnnotation.swift +++ /dev/null @@ -1,20 +0,0 @@ -protocol MapContentAnnotation { - var id: String { get set } - var isDraggable: Bool { get set } - var isSelected: Bool { get set } -} - -protocol MapContentAnnotationManager: AnyObject { - associatedtype AnnotationType: MapContentAnnotation - var layerPosition: LayerPosition? { get set } - var isSwiftUI: Bool { get set } - - func set(newAnnotations: [(AnyHashable, AnnotationType)]) - - static func make( - layerId: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions?, - using orchestrator: AnnotationOrchestrator - ) -> Self -} diff --git a/Sources/MapboxMaps/ContentBuilders/MapContent/MountedAnnotationGroup.swift b/Sources/MapboxMaps/ContentBuilders/MapContent/MountedAnnotationGroup.swift index d5bea39a7a1c..356fda6b0256 100644 --- a/Sources/MapboxMaps/ContentBuilders/MapContent/MountedAnnotationGroup.swift +++ b/Sources/MapboxMaps/ContentBuilders/MapContent/MountedAnnotationGroup.swift @@ -1,17 +1,17 @@ import os.log @available(iOS 13.0, *) -struct MountedAnnotationGroup: MapContentMountedComponent { - private let annotations: [(AnyHashable, M.AnnotationType)] +struct MountedAnnotationGroup: MapContentMountedComponent { + private let annotations: [(AnyHashable, Manager.Traits.AnnotationType)] private let layerId: String private let clusterOptions: ClusterOptions? - private let updateProperties: (M) -> Void + private let updateProperties: (Manager) -> Void init( layerId: String, clusterOptions: ClusterOptions?, - annotations: [(AnyHashable, M.AnnotationType)], - updateProperties: @escaping (M) -> Void + annotations: [(AnyHashable, Manager.Traits.AnnotationType)], + updateProperties: @escaping (Manager) -> Void ) { self.layerId = layerId self.clusterOptions = clusterOptions @@ -26,15 +26,9 @@ struct MountedAnnotationGroup: MapContentMounted os_log(.debug, log: .contentDSL, "Annotation add %s", layerId) - let manager = M.make( - layerId: layerId, - layerPosition: context.resolveLayerPosition(), - clusterOptions: clusterOptions, - using: orchestrator - ) - manager.isSwiftUI = true - updateProperties(manager) - manager.set(newAnnotations: annotations) + let manager: Manager = orchestrator.make(AnnotationManagerParams(id: layerId, layerPosition: context.resolveLayerPosition(), clusterOptions: clusterOptions)) + + update(manager: manager, context: context) } func unmount(with context: MapContentNodeContext) throws { @@ -49,20 +43,24 @@ struct MountedAnnotationGroup: MapContentMounted } guard let orchestrator = context.content?.layerAnnotations.value, - let manager = orchestrator.annotationManagersById[layerId] as? M else { + let manager = orchestrator.annotationManagersById[layerId] as? Manager else { return false } os_log(.debug, log: .contentDSL, "Annotation update %s", layerId) - manager.isSwiftUI = true - updateProperties(manager) - manager.layerPosition = context.resolveLayerPosition() - manager.set(newAnnotations: annotations) + update(manager: manager, context: context) return true } + private func update(manager: Manager, context: MapContentNodeContext) { + manager.impl.isSwiftUI = true + updateProperties(manager) + manager.impl.layerPosition = context.resolveLayerPosition() + manager.impl.set(newAnnotations: annotations) + } + func updateMetadata(with context: MapContentNodeContext) { context.lastLayerId = layerId } diff --git a/Sources/MapboxMaps/Foundation/MapView.swift b/Sources/MapboxMaps/Foundation/MapView.swift index da99c054a4e4..1ce6b677e072 100644 --- a/Sources/MapboxMaps/Foundation/MapView.swift +++ b/Sources/MapboxMaps/Foundation/MapView.swift @@ -374,23 +374,15 @@ open class MapView: UIView, SizeTrackingLayerDelegate { cameraAnimatorsRunner: cameraAnimatorsRunner) camera = CameraAnimationsManager(impl: internalCamera) - let annotationsImpl = dependencyProvider.makeAnnotationOrchestratorImpl( - in: self, - mapboxMap: mapboxMap, - mapFeatureQueryable: mapboxMap, - style: mapboxMap, - displayLink: displayLinkSignalSubject.signal - ) - annotations = AnnotationOrchestrator( - impl: annotationsImpl - ) + deps: .from(mapboxMap: mapboxMap, displayLink: displayLinkSignalSubject.signal)) + // Initialize/Configure gesture manager gestures = dependencyProvider.makeGestureManager( view: self, mapboxMap: mapboxMap, mapFeatureQueryable: mapboxMap, - annotations: annotationsImpl, + annotationManagersByLayerId: annotations.$managersByLayerId, cameraAnimationsManager: internalCamera) // Initialize the attribution manager diff --git a/Sources/MapboxMaps/Foundation/MapViewDependencyProvider.swift b/Sources/MapboxMaps/Foundation/MapViewDependencyProvider.swift index 1c84f4d37af1..5caa191bbf06 100644 --- a/Sources/MapboxMaps/Foundation/MapViewDependencyProvider.swift +++ b/Sources/MapboxMaps/Foundation/MapViewDependencyProvider.swift @@ -12,7 +12,7 @@ protocol MapViewDependencyProviderProtocol: AnyObject { func makeGestureManager(view: UIView, mapboxMap: MapboxMapProtocol, mapFeatureQueryable: MapFeatureQueryable, - annotations: AnnotationOrchestratorImplProtocol, + annotationManagersByLayerId: Ref<[String: AnnotationManagerImplProtocol]>, cameraAnimationsManager: CameraAnimationsManagerProtocol) -> GestureManager // swiftlint:disable:next function_parameter_count func makeViewportManagerImpl(mapboxMap: MapboxMapProtocol, @@ -22,13 +22,6 @@ protocol MapViewDependencyProviderProtocol: AnyObject { anyTouchGestureRecognizer: UIGestureRecognizer, doubleTapGestureRecognizer: UIGestureRecognizer, doubleTouchGestureRecognizer: UIGestureRecognizer) -> ViewportManagerImplProtocol - func makeAnnotationOrchestratorImpl( - in view: UIView, - mapboxMap: MapboxMapProtocol, - mapFeatureQueryable: MapFeatureQueryable, - style: StyleProtocol, - displayLink: Signal - ) -> AnnotationOrchestratorImplProtocol func makeEventsManager() -> EventsManagerProtocol } @@ -185,7 +178,7 @@ final class MapViewDependencyProvider: MapViewDependencyProviderProtocol { view: UIView, mapboxMap: MapboxMapProtocol, mapFeatureQueryable: MapFeatureQueryable, - annotations: AnnotationOrchestratorImplProtocol, + annotationManagersByLayerId: Ref<[String: AnnotationManagerImplProtocol]>, cameraAnimationsManager: CameraAnimationsManagerProtocol ) -> GestureManager { let singleTap = makeSingleTapGestureHandler( @@ -196,7 +189,7 @@ final class MapViewDependencyProvider: MapViewDependencyProviderProtocol { view.addGestureRecognizer(longPress.recognizer) let mapContentGestureManager = MapContentGestureManager( - annotations: annotations, + annotationManagersByLayerId: annotationManagersByLayerId, mapboxMap: mapboxMap, mapFeatureQueryable: mapFeatureQueryable, onTap: singleTap.onTap, @@ -235,26 +228,6 @@ final class MapViewDependencyProvider: MapViewDependencyProviderProtocol { mapContentGestureManager: mapContentGestureManager) } - func makeAnnotationOrchestratorImpl( - in view: UIView, - mapboxMap: MapboxMapProtocol, - mapFeatureQueryable: MapFeatureQueryable, - style: StyleProtocol, - displayLink: Signal - ) -> AnnotationOrchestratorImplProtocol { - let offsetPointCalculator = OffsetPointCalculator(mapboxMap: mapboxMap) - let offsetLineStringCalculator = OffsetLineStringCalculator(mapboxMap: mapboxMap) - let offsetPolygonCalculator = OffsetPolygonCalculator(mapboxMap: mapboxMap) - let factory = AnnotationManagerFactory( - style: style, - displayLink: displayLink, - offsetPointCalculator: offsetPointCalculator, - offsetPolygonCalculator: offsetPolygonCalculator, - offsetLineStringCalculator: offsetLineStringCalculator, - mapFeatureQueryable: mapFeatureQueryable) - return AnnotationOrchestratorImpl(factory: factory) - } - // swiftlint:disable:next function_parameter_count internal func makeViewportManagerImpl( mapboxMap: MapboxMapProtocol, diff --git a/Sources/MapboxMaps/Gestures/MapContentGestureManager.swift b/Sources/MapboxMaps/Gestures/MapContentGestureManager.swift index 0201e9d54b05..8388ec842037 100644 --- a/Sources/MapboxMaps/Gestures/MapContentGestureManager.swift +++ b/Sources/MapboxMaps/Gestures/MapContentGestureManager.swift @@ -14,14 +14,14 @@ final class MapContentGestureManager: MapContentGestureManagerProtocol { private typealias LayerTapGestureParams = (QueriedFeature, MapContentGestureContext) private typealias LayerSubscribersStore = ClosureHandlersStore - private typealias ManagerHandlerBlock = (AnnotationManagerInternal) -> (String, Feature, MapContentGestureContext) -> Bool + private typealias ManagerHandlerBlock = (AnnotationManagerImplProtocol) -> (String, Feature, MapContentGestureContext) -> Bool private struct DragState { var point: CGPoint - let manager: AnnotationManagerInternal + let manager: AnnotationManagerImplProtocol } - private let annotations: AnnotationOrchestratorImplProtocol + private let annotations: Ref<[String: AnnotationManagerImplProtocol]> private let mapboxMap: MapboxMapProtocol private let mapFeatureQueryable: MapFeatureQueryable @@ -34,13 +34,13 @@ final class MapContentGestureManager: MapContentGestureManagerProtocol { private var layerLongPressSubscribers = [String: LayerSubscribersStore]() init( - annotations: AnnotationOrchestratorImplProtocol, + annotationManagersByLayerId: Ref<[String: AnnotationManagerImplProtocol]>, mapboxMap: MapboxMapProtocol, mapFeatureQueryable: MapFeatureQueryable, onTap: Signal, onLongPress: Signal<(CGPoint, UIGestureRecognizer.State)> ) { - self.annotations = annotations + self.annotations = annotationManagersByLayerId self.mapboxMap = mapboxMap self.mapFeatureQueryable = mapFeatureQueryable onTap @@ -146,7 +146,7 @@ final class MapContentGestureManager: MapContentGestureManagerProtocol { } for (layerId, queriedFeature) in queriedFeatures { - if let manager = annotations.managersByLayerId[layerId], let featureId = queriedFeature.feature.stringId { + if let manager = annotations.value[layerId], let featureId = queriedFeature.feature.stringId { if manager.handleDragBegin(with: featureId, context: context) { dragState = DragState(point: context.point, manager: manager) return @@ -161,7 +161,7 @@ final class MapContentGestureManager: MapContentGestureManagerProtocol { context: MapContentGestureContext ) -> Bool { let (layerId, queriedFeature) = queriedFeature - if let manager = annotations.managersByLayerId[layerId], + if let manager = annotations.value[layerId], handledUsing(manager)(layerId, queriedFeature.feature, context) { return true } @@ -187,7 +187,7 @@ final class MapContentGestureManager: MapContentGestureManagerProtocol { subscribers: KeyPath? = nil, handler: @escaping ([(String, QueriedFeature)], MapContentGestureContext) -> Void ) { - var layerIds = Array(annotations.managersByLayerId.keys) + var layerIds = Array(annotations.value.keys) if let subscribers { layerIds += self[keyPath: subscribers].keys } queryToken = mapFeatureQueryable.queryRenderedFeatures(point: context.point, layerIds: layerIds) { queriedFeatures in handler(queriedFeatures, context) diff --git a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/CircleAnnotationGroup.swift b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/CircleAnnotationGroup.swift index ecd2f82a9f4c..b7c2b7cf694a 100644 --- a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/CircleAnnotationGroup.swift +++ b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/CircleAnnotationGroup.swift @@ -153,16 +153,4 @@ extension CircleAnnotationGroup: MapContent, PrimitiveMapContent { } } -@available(iOS 13.0, *) -extension CircleAnnotationManager: MapContentAnnotationManager { - static func make( - layerId: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions? = nil, - using orchestrator: AnnotationOrchestrator - ) -> Self { - orchestrator.makeCircleAnnotationManager(id: layerId, layerPosition: layerPosition) as! Self - } -} - // End of generated file. diff --git a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PointAnnotationGroup.swift b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PointAnnotationGroup.swift index 94ed140211d8..137301fa4499 100644 --- a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PointAnnotationGroup.swift +++ b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PointAnnotationGroup.swift @@ -386,16 +386,4 @@ extension PointAnnotationGroup: MapContent, PrimitiveMapContent { } } -@available(iOS 13.0, *) -extension PointAnnotationManager: MapContentAnnotationManager { - static func make( - layerId: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions? = nil, - using orchestrator: AnnotationOrchestrator - ) -> Self { - orchestrator.makePointAnnotationManager(id: layerId, layerPosition: layerPosition, clusterOptions: clusterOptions) as! Self - } -} - // End of generated file. diff --git a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolygonAnnotationGroup.swift b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolygonAnnotationGroup.swift index d505e43b54c3..9405fe0e6ffe 100644 --- a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolygonAnnotationGroup.swift +++ b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolygonAnnotationGroup.swift @@ -141,16 +141,4 @@ extension PolygonAnnotationGroup: MapContent, PrimitiveMapContent { } } -@available(iOS 13.0, *) -extension PolygonAnnotationManager: MapContentAnnotationManager { - static func make( - layerId: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions? = nil, - using orchestrator: AnnotationOrchestrator - ) -> Self { - orchestrator.makePolygonAnnotationManager(id: layerId, layerPosition: layerPosition) as! Self - } -} - // End of generated file. diff --git a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolylineAnnotationGroup.swift b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolylineAnnotationGroup.swift index 24bd7e300ab2..dc3891d7fb66 100644 --- a/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolylineAnnotationGroup.swift +++ b/Sources/MapboxMaps/SwiftUI/Annotations/Generated/PolylineAnnotationGroup.swift @@ -212,16 +212,4 @@ extension PolylineAnnotationGroup: MapContent, PrimitiveMapContent { } } -@available(iOS 13.0, *) -extension PolylineAnnotationManager: MapContentAnnotationManager { - static func make( - layerId: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions? = nil, - using orchestrator: AnnotationOrchestrator - ) -> Self { - orchestrator.makePolylineAnnotationManager(id: layerId, layerPosition: layerPosition) as! Self - } -} - // End of generated file. diff --git a/Tests/MapboxMapsTests/Annotations/AnnotationManagerFactoryTests.swift b/Tests/MapboxMapsTests/Annotations/AnnotationManagerFactoryTests.swift deleted file mode 100644 index ed0c638cb348..000000000000 --- a/Tests/MapboxMapsTests/Annotations/AnnotationManagerFactoryTests.swift +++ /dev/null @@ -1,93 +0,0 @@ -import Foundation -import XCTest -@testable import MapboxMaps - -final class AnnotationManagerFactoryTests: XCTestCase { - var style: MockStyle! - var offsetPointCalculator: OffsetPointCalculator! - var offsetLineStringCalculator: OffsetLineStringCalculator! - var offsetPolygonCalculator: OffsetPolygonCalculator! - var mapFeatureQueryable: MapFeatureQueryable! - var factory: AnnotationManagerFactory! - @TestSignal var displayLink: Signal - - override func setUp() { - super.setUp() - - style = MockStyle() - offsetPointCalculator = OffsetPointCalculator(mapboxMap: MockMapboxMap()) - offsetLineStringCalculator = OffsetLineStringCalculator(mapboxMap: MockMapboxMap()) - offsetPolygonCalculator = OffsetPolygonCalculator(mapboxMap: MockMapboxMap()) - mapFeatureQueryable = MockMapFeatureQueryable() - factory = AnnotationManagerFactory( - style: style, - displayLink: displayLink, - offsetPointCalculator: offsetPointCalculator, - offsetPolygonCalculator: offsetPolygonCalculator, - offsetLineStringCalculator: offsetLineStringCalculator, - mapFeatureQueryable: mapFeatureQueryable) - } - - override func tearDown() { - super.tearDown() - - style = nil - offsetPointCalculator = nil - offsetLineStringCalculator = nil - offsetPolygonCalculator = nil - mapFeatureQueryable = nil - factory = nil - } - - // test return values for factory - func testReturnedPointAnnotationManager() { - let id = "managerId" - let layerPosition: LayerPosition = .at(50) - let clusterOptions = ClusterOptions() - - //when - let manager = factory.makePointAnnotationManager(id: id, layerPosition: layerPosition, clusterOptions: clusterOptions) - - //then - XCTAssertTrue(manager is PointAnnotationManager) - - } - - func testReturnedPolygonAnnotationManager() { - let id = "managerId" - let layerPosition: LayerPosition? = .at(81) - - //when - let manager = factory.makePolygonAnnotationManager(id: id, layerPosition: layerPosition) - - //then - XCTAssertTrue(manager is PolygonAnnotationManager) - - } - - func testReturnedPolylineAnnotationManager() { - let id = "managerId" - let layerPosition: LayerPosition? = .at(56) - - //when - let manager = factory.makePolylineAnnotationManager(id: id, layerPosition: layerPosition) - - //then - XCTAssertTrue(manager is PolylineAnnotationManager) - - } - - func testReturnedCircleAnnotationManager() { - //given - let id = "managerId" - let layerPosition: LayerPosition? = .at(18) - - //when - let manager = factory.makeCircleAnnotationManager(id: id, layerPosition: layerPosition) - - //then - XCTAssertTrue(manager is CircleAnnotationManager) - - } - -} diff --git a/Tests/MapboxMapsTests/Annotations/AnnotationManagerImplTests.swift b/Tests/MapboxMapsTests/Annotations/AnnotationManagerImplTests.swift new file mode 100644 index 000000000000..6ecf433e35f7 --- /dev/null +++ b/Tests/MapboxMapsTests/Annotations/AnnotationManagerImplTests.swift @@ -0,0 +1,741 @@ +@testable import MapboxMaps +import XCTest + +final class AnnotationManagerImplTests: XCTestCase { + private var harness: AnnotationManagerTestingHarness! + private var style: MockStyle { harness.style } + private var me: AnnotationManagerImpl! + private var annotations = [PointAnnotation]() + + let id = "default" + var layerIds: [String] { + [ + "mapbox-iOS-cluster-circle-layer-manager-\(id)", + "mapbox-iOS-cluster-text-layer-manager-\(id)", + id + ] + } + + class Delegate: AnnotationManagerImplDelegate { + var annotations: [any Annotation]? + var syncImagesCount = 0 + var removeImagesCount = 0 + func didTap(_ annotations: [any Annotation]) { + self.annotations = annotations + } + func syncImages() { syncImagesCount += 1 } + func removeAllImages() { removeImagesCount += 1 } + } + + override func setUp() { + super.setUp() + harness = AnnotationManagerTestingHarness() + + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: ClusterOptions()), + deps: harness.makeDeps()) + + annotations = (0...10).map { + PointAnnotation( + coordinate: .init(latitude: LocationDegrees($0), longitude: LocationDegrees($0)), isSelected: false, isDraggable: false) + } + } + + override func tearDown() { + me = nil + harness = nil + annotations = [] + super.tearDown() + } + + func testSetup() throws { + style.addSourceStub.reset() + + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: "foo", + layerPosition: .at(4), + clusterOptions: nil), + deps: harness.makeDeps()) + + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + XCTAssertEqual(style.addPersistentLayerWithPropertiesStub.invocations.count, 0) + XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.type, LayerType.symbol) + XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.id, "foo") + let addedLayer = try XCTUnwrap(style.addPersistentLayerStub.invocations.last?.parameters.layer as? SymbolLayer) + XCTAssertEqual(addedLayer.source, "foo") + XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition, LayerPosition.at(4)) + } + + func testDestroy() { + me.destroy() + + XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), layerIds) + XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id]) + + style.removeLayerStub.reset() + style.removeSourceStub.reset() + + me.destroy() + XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) + XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) + } + + func testDestroyManagerWithDraggedAnnotations() { + var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) + annotation.isDraggable = true + me.annotations = [annotation] + // adds drag source/layer + _ = me.handleDragBegin(with: annotation.id, context: .zero) + + me.destroy() + + XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), layerIds + [id + "_drag"]) + XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id, id + "_drag"]) + + style.removeLayerStub.reset() + style.removeSourceStub.reset() + + me.destroy() + XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) + XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) + } + + func testSyncSourceAndLayer() { + me.annotations = annotations + harness.triggerDisplayLink() + + XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) + } + + func testDoNotSyncSourceAndLayerWhenNotNeeded() { + harness.$displayLink.send() + + XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 0) + } + + func testFeatureCollectionPassedToGeoJSON() throws { + let expectedFeatures = annotations.map(\.feature) + + me.annotations = annotations + harness.triggerDisplayLink() + + var invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) + XCTAssertEqual(invocation.parameters.features, expectedFeatures) + XCTAssertEqual(invocation.parameters.sourceId, "default") + + do { + let annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) + annotations.append(annotation) + + me.annotations = annotations + harness.triggerDisplayLink() + + invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) + XCTAssertEqual(invocation.parameters.features, [annotation].map(\.feature)) + XCTAssertEqual(invocation.parameters.sourceId, "default") + } + } + + func testLayerSync() throws { + func checkExpression(key: String, props: [String: Any]) throws { + let value = try XCTUnwrap(props[key] as? [Any]) + XCTAssertEqual(value[safe: 0] as? String, "get") + XCTAssertEqual(value[safe: 1] as? String, key) + XCTAssertEqual(value[safe: 2] as? [String], ["get", "layerProperties"]) + } + + me.annotations = annotations + let delegate = Delegate() + me.delegate = delegate + harness.triggerDisplayLink() + + XCTAssertEqual(delegate.syncImagesCount, 1) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, id) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, 0) + + style.setLayerPropertiesStub.reset() + + // Add properties + me.annotations = [ + PointAnnotation(id: "foo", coordinate: .init(latitude: 0, longitude: 0)) + .textSize(10) + ] + me.layerProperties["bar"] = "Bar" + me.layerProperties["baz"] = "Baz" + me.layerProperties["icon-allow-overlap"] = true + + harness.triggerDisplayLink() + + XCTAssertEqual(delegate.syncImagesCount, 2) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, id) + + let props = try XCTUnwrap(style.setLayerPropertiesStub.invocations.last?.parameters.properties) + XCTAssertEqual(props["bar"] as? String, "Bar") + XCTAssertEqual(props["baz"] as? String, "Baz") + XCTAssertEqual(props["icon-allow-overlap"] as? Bool, true) + try checkExpression(key: "text-size", props: props) + XCTAssertEqual(props.count, 4) + + style.setLayerPropertiesStub.reset() + + // Update with other properties + me.annotations = [ + PointAnnotation(id: "foo", coordinate: .init(latitude: 0, longitude: 0)) + .textSize(20) + .textField("Bar") + ] + me.layerProperties["x"] = "X" + me.layerProperties["bar"] = "qux" + me.layerProperties.removeValue(forKey: "icon-allow-overlap") // expected to reset unused prop to default + + harness.triggerDisplayLink() + + XCTAssertEqual(delegate.syncImagesCount, 3) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) + XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, id) + + let props2 = try XCTUnwrap(style.setLayerPropertiesStub.invocations.last?.parameters.properties) + XCTAssertEqual(props2["x"] as? String, "X") + XCTAssertEqual(props2["bar"] as? String, "qux") + + // resets to default + let def = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-allow-overlap").value as? Bool + XCTAssertEqual(props2["icon-allow-overlap"] as? Bool, def) + + try checkExpression(key: "text-field", props: props2) + XCTAssertEqual(props2.count, 6) + } + + @available(*, deprecated) + func testHandleTap() throws { + let delegate = Delegate() + var taps = [MapContentGestureContext]() + annotations[0].tapHandler = { context in + taps.append(context) + return true + } + annotations[1].tapHandler = { _ in + return false // skips handling + } + me.delegate = delegate + me.annotations = annotations + + // first annotation, handles tap + let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) + var handled = me.handleTap(layerId: "layerId", feature: annotations[0].feature, context: context) + + var result = try XCTUnwrap(delegate.annotations) + XCTAssertEqual(result[0].id, annotations[0].id) + XCTAssertEqual(handled, true) + + XCTAssertEqual(taps.count, 1) + XCTAssertEqual(taps.first?.point, context.point) + XCTAssertEqual(taps.first?.coordinate, context.coordinate) + + // second annotation, skips handling tap + delegate.annotations = nil + handled = me.handleTap(layerId: "layerId", feature: annotations[1].feature, context: context) + + result = try XCTUnwrap(delegate.annotations) + XCTAssertEqual(result[0].id, annotations[1].id) + XCTAssertEqual(handled, false) + + // invalid id + delegate.annotations = nil + let invalidFeature = Feature(geometry: nil) + handled = me.handleTap(layerId: "layerId", feature: invalidFeature, context: context) + + XCTAssertNil(delegate.annotations) + XCTAssertEqual(handled, false) + XCTAssertEqual(taps.count, 1) + } + + func testHandleLongPress() throws { + var taps = [MapContentGestureContext]() + annotations[0].longPressHandler = { context in + taps.append(context) + return true + } + me.annotations = annotations + + // first annotation, handles tap + let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) + var handled = me.handleLongPress(layerId: "layerId", feature: annotations[0].feature, context: context) + + XCTAssertEqual(handled, true) + + XCTAssertEqual(taps.count, 1) + XCTAssertEqual(taps.first?.point, context.point) + XCTAssertEqual(taps.first?.coordinate, context.coordinate) + + // second annotation, skips handling tap + handled = me.handleLongPress(layerId: "layerId", feature: annotations[1].feature, context: context) + + XCTAssertEqual(handled, false) + + // invalid id + let invalidFeature = Feature(geometry: nil) + handled = me.handleLongPress(layerId: "layerId", feature: invalidFeature, context: context) + + XCTAssertEqual(handled, false) + XCTAssertEqual(taps.count, 1) + } + + func testHandleClusterTap() { + let onClusterTap = Stub(defaultReturnValue: ()) + let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) + let annotationContext = AnnotationClusterGestureContext(point: context.point, coordinate: context.coordinate, expansionZoom: 4) + me.onClusterTap = onClusterTap.call + + let isHandled = me.handleTap( + layerId: "mapbox-iOS-cluster-circle-layer-manager-default", + feature: annotations[1].feature, + context: context + ) + harness.mapFeatureQueryable.getGeoJsonClusterExpansionZoomStub.invocations.map(\.parameters.completion).forEach { completion in + completion(.success(FeatureExtensionValue(value: 4, features: nil))) + } + + XCTAssertTrue(isHandled) + XCTAssertEqual(harness.mapFeatureQueryable.getGeoJsonClusterExpansionZoomStub.invocations.map(\.parameters.feature), [ + annotations[1].feature + ]) + + XCTAssertEqual(onClusterTap.invocations.map(\.parameters), [annotationContext]) + } + + func testHandleClusterLongPress() { + let onClusterLongPress = Stub(defaultReturnValue: ()) + let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) + let annotationContext = AnnotationClusterGestureContext(point: context.point, coordinate: context.coordinate, expansionZoom: 4) + me.onClusterLongPress = onClusterLongPress.call + + let isHandled = me.handleLongPress( + layerId: "mapbox-iOS-cluster-circle-layer-manager-default", + feature: annotations[1].feature, + context: context + ) + harness.mapFeatureQueryable.getGeoJsonClusterExpansionZoomStub.invocations.map(\.parameters.completion).forEach { completion in + completion(.success(FeatureExtensionValue(value: 4, features: nil))) + } + + XCTAssertTrue(isHandled) + XCTAssertEqual(harness.mapFeatureQueryable.getGeoJsonClusterExpansionZoomStub.invocations.map(\.parameters.feature), [ + annotations[1].feature + ]) + + XCTAssertEqual(onClusterLongPress.invocations.map(\.parameters), [annotationContext]) + } + + // MARK: - Clustering tests + func testInitWithDefaultClusterOptions() { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + // given + let clusterOptions = ClusterOptions() + var annotations = [PointAnnotation]() + for _ in 0...500 { + let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + annotations.append(annotation) + } + + // when + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: clusterOptions), + deps: harness.makeDeps()) + + me.annotations = annotations + + // then + XCTAssertEqual(clusterOptions.clusterRadius, 50) + XCTAssertEqual(clusterOptions.circleRadius, .constant(18)) + XCTAssertEqual(clusterOptions.circleColor, .constant(StyleColor(.black))) + XCTAssertEqual(clusterOptions.textColor, .constant(StyleColor(.white))) + XCTAssertEqual(clusterOptions.textSize, .constant(12)) + XCTAssertEqual(clusterOptions.textField, .expression(Exp(.get) { "point_count" })) + XCTAssertEqual(clusterOptions.clusterMaxZoom, 14) + XCTAssertNil(clusterOptions.clusterProperties) + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.type, SourceType.geoJson) + XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.id, id) + XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 3) // symbol layer, one cluster layer, one text layer + XCTAssertNil(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition) + } + + func testSourceClusterOptions() throws { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + // given + let testClusterRadius = Double.testSourceValue() + let testClusterMaxZoom = Double.testSourceValue() + let testClusterProperties = [String: Exp].testSourceValue() + let clusterOptions = ClusterOptions(clusterRadius: testClusterRadius, + clusterMaxZoom: testClusterMaxZoom, + clusterProperties: testClusterProperties) + var annotations = [PointAnnotation]() + for _ in 0...500 { + let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + annotations.append(annotation) + } + + // when + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: clusterOptions), + deps: harness.makeDeps()) + + me.annotations = annotations + let geoJSONSource = try XCTUnwrap(style.addSourceStub.invocations.last?.parameters.source as? GeoJSONSource) + + // then + XCTAssertTrue(geoJSONSource.cluster!) + XCTAssertEqual(clusterOptions.clusterRadius, testClusterRadius) + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + XCTAssertEqual(geoJSONSource.clusterRadius, testClusterRadius) + XCTAssertEqual(geoJSONSource.clusterMaxZoom, testClusterMaxZoom) + XCTAssertEqual(geoJSONSource.clusterProperties, testClusterProperties) + } + + func testCircleLayer() throws { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + // given + let testCircleRadius = Value.testConstantValue() + let testCircleColor = Value.testConstantValue() + let clusterOptions = ClusterOptions(circleRadius: testCircleRadius, + circleColor: testCircleColor) + var annotations = [PointAnnotation]() + for _ in 0...500 { + let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + annotations.append(annotation) + } + + // when + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: clusterOptions), + deps: harness.makeDeps()) + me.annotations = annotations + + // then + let circleLayerInvocations = style.addPersistentLayerStub.invocations.filter { circleLayer in + return circleLayer.parameters.layer.id == "mapbox-iOS-cluster-circle-layer-manager-" + id + } + let circleLayer = try XCTUnwrap(circleLayerInvocations[0].parameters.layer as? CircleLayer) + + XCTAssertEqual(clusterOptions.circleRadius, testCircleRadius) + XCTAssertEqual(circleLayer.circleRadius, testCircleRadius) + XCTAssertEqual(clusterOptions.circleColor, testCircleColor) + XCTAssertEqual(circleLayer.circleColor, testCircleColor) + XCTAssertEqual(circleLayer.filter, Exp(.has) { "point_count" }) + XCTAssertEqual(circleLayer.id, "mapbox-iOS-cluster-circle-layer-manager-" + id) + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + } + + func testTextLayer() throws { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + // given + let testTextColor = Value.testConstantValue() + let testTextSize = Value.testConstantValue() + let testTextField = Value.testConstantValue() + let clusterOptions = ClusterOptions(textColor: testTextColor, + textSize: testTextSize, + textField: testTextField) + var annotations = [PointAnnotation]() + for _ in 0...500 { + let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + annotations.append(annotation) + } + + // when + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: clusterOptions), + deps: harness.makeDeps()) + me.annotations = annotations + + // then + let textLayerInvocations = style.addPersistentLayerStub.invocations.filter { symbolLayer in + return symbolLayer.parameters.layer.id == "mapbox-iOS-cluster-text-layer-manager-" + id + } + let textLayer = try XCTUnwrap(textLayerInvocations[0].parameters.layer as? SymbolLayer) + + XCTAssertEqual(textLayer.textColor, testTextColor) + XCTAssertEqual(textLayer.textSize, testTextSize) + XCTAssertEqual(textLayer.textField, testTextField) + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + } + + func testSymbolLayers() throws { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + // given + let clusterOptions = ClusterOptions() + var annotations = [PointAnnotation]() + for _ in 0...500 { + let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + annotations.append(annotation) + } + + // when + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: clusterOptions), + deps: harness.makeDeps()) + me.annotations = annotations + + // then + let symbolLayerInvocations = style.addPersistentLayerStub.invocations.filter { symbolLayer in + return symbolLayer.parameters.layer.id == id + } + let symbolLayer = try XCTUnwrap(symbolLayerInvocations[0].parameters.layer as? SymbolLayer) + + XCTAssertTrue(symbolLayer.iconAllowOverlap == .constant(true)) + XCTAssertTrue(symbolLayer.textAllowOverlap == .constant(true)) + XCTAssertTrue(symbolLayer.iconIgnorePlacement == .constant(true)) + XCTAssertTrue(symbolLayer.textIgnorePlacement == .constant(true)) + XCTAssertEqual(symbolLayer.source, id) + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + } + + func testChangeAnnotations() throws { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + // given + let clusterOptions = ClusterOptions() + let annotations = (0..<500).map { _ in + PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + } + let newAnnotations = (0..<100).map { _ in + PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + } + + // when + me = AnnotationManagerImpl( + params: AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: clusterOptions), + deps: harness.makeDeps()) + me.annotations = annotations + harness.triggerDisplayLink() + + let parameters = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last).parameters + XCTAssertEqual(parameters.features, annotations.map(\.feature)) + + // then + me.annotations = newAnnotations + harness.triggerDisplayLink() + + let addParameters = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last).parameters + XCTAssertEqual(addParameters.features, newAnnotations.map(\.feature)) + + let removeParameters = try XCTUnwrap(style.removeGeoJSONSourceFeaturesStub.invocations.last).parameters + XCTAssertEqual(removeParameters.featureIds, annotations.map(\.id)) + } + + // MARK: - Draggable + + func testGetDraggedAnnotations() { + let annotations = Array.random(withLength: 10) { + PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) + } + me.annotations = annotations + + // Dragged annotation will be added to internal list of dragged annotations. + let annotationToDrag = annotations.randomElement()! + _ = me.handleDragBegin(with: annotationToDrag.id, context: .zero) + XCTAssertTrue(me.annotations.contains(where: { $0.id == annotationToDrag.id })) + } + + func testHandleDragBeginIsDraggableFalse() throws { + me.annotations = [ + PointAnnotation(id: "point1", coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) + ] + + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + + _ = me.handleDragBegin(with: "point1", context: .zero) + + XCTAssertEqual(style.addSourceStub.invocations.count, 0) + XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 0) + } + + func testHandleDragBeginInvalidFeatureId() { + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + + _ = me.handleDragBegin(with: "not-a-feature", context: .zero) + + XCTAssertTrue(style.addSourceStub.invocations.isEmpty) + XCTAssertTrue(style.addPersistentLayerStub.invocations.isEmpty) + } + + func testDrag() throws { + let annotation = PointAnnotation(id: "point1", coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) + me.annotations = [annotation] + + style.addSourceStub.reset() + style.addPersistentLayerStub.reset() + _ = me.handleDragBegin(with: "point1", context: .zero) + + let addSourceParameters = try XCTUnwrap(style.addSourceStub.invocations.last).parameters + let addLayerParameters = try XCTUnwrap(style.addPersistentLayerStub.invocations.last).parameters + + let addedLayer = try XCTUnwrap(addLayerParameters.layer as? SymbolLayer) + XCTAssertEqual(addedLayer.source, addSourceParameters.source.id) + XCTAssertEqual(addLayerParameters.layerPosition, .above(id)) + XCTAssertEqual(addedLayer.id, id + "_drag") + + XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) + harness.triggerDisplayLink() + XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 1) + XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.last?.parameters.id, "\(id)_drag") + + _ = me.handleDragBegin(with: "point1", context: .zero) + + XCTAssertEqual(style.addSourceStub.invocations.count, 1) + XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 1) + + harness.map.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) + harness.map.coordinateForPointStub.defaultReturnValue = .init(latitude: 0, longitude: 0) + harness.map.cameraState.zoom = 1 + + me.handleDragChange(with: .zero, context: .zero) + + harness.triggerDisplayLink() + + let updateSourceParameters = try XCTUnwrap(style.updateGeoJSONSourceStub.invocations.last).parameters + XCTAssertTrue(updateSourceParameters.id == addSourceParameters.source.id) + if case .featureCollection(let collection) = updateSourceParameters.geojson { + XCTAssertTrue(collection.features.contains(where: { $0.identifier?.rawValue as? String == annotation.id })) + } else { + XCTFail("GeoJSONObject should be a feature collection") + } + } + + func testDragHandlers() throws { + struct GestureData { + var annotation: PointAnnotation + var context: MapContentGestureContext + } + + var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) + annotation.isDraggable = true + + let beginDragStub = Stub(defaultReturnValue: false) + let changeDragStub = Stub() + let endDragStub = Stub() + annotation.dragBeginHandler = { annotation, context in + beginDragStub.call(with: GestureData(annotation: annotation, context: context)) + } + annotation.dragChangeHandler = { annotation, context in + changeDragStub.call(with: GestureData(annotation: annotation, context: context)) + } + annotation.dragEndHandler = { annotation, context in + endDragStub.call(with: GestureData(annotation: annotation, context: context)) + } + me.annotations = [annotation] + + harness.map.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) + harness.map.coordinateForPointStub.defaultReturnValue = .init(latitude: 23.5432356, longitude: -12.5326744) + harness.map.cameraState.zoom = 1 + + var context = MapContentGestureContext(point: CGPoint(x: 0, y: 1), coordinate: .init(latitude: 2, longitude: 3)) + + // test it twice to cover the case when annotation was already on drag layer. + for _ in 0...1 { + beginDragStub.reset() + changeDragStub.reset() + endDragStub.reset() + + // skipped gesture + beginDragStub.defaultReturnValue = false + var res = me.handleDragBegin(with: annotation.id, context: context) + XCTAssertEqual(beginDragStub.invocations.count, 1) + XCTAssertEqual(res, false) + var data = try XCTUnwrap(beginDragStub.invocations.last).parameters + XCTAssertEqual(data.annotation.id, annotation.id) + XCTAssertEqual(data.context.point, context.point) + XCTAssertEqual(data.context.coordinate, context.coordinate) + + me.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) + me.handleDragEnd(context: context) + XCTAssertEqual(changeDragStub.invocations.count, 0) + XCTAssertEqual(endDragStub.invocations.count, 0) + + // handled gesture + context.point.x += 1 + context.coordinate.latitude += 1 + beginDragStub.defaultReturnValue = true + res = me.handleDragBegin(with: annotation.id, context: context) + XCTAssertEqual(beginDragStub.invocations.count, 2) + XCTAssertEqual(res, true) + data = try XCTUnwrap(beginDragStub.invocations.last).parameters + XCTAssertEqual(data.annotation.id, annotation.id) + XCTAssertEqual(data.context.point, context.point) + XCTAssertEqual(data.context.coordinate, context.coordinate) + + context.point.x += 1 + context.coordinate.latitude += 1 + me.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) + XCTAssertEqual(changeDragStub.invocations.count, 1) + data = try XCTUnwrap(changeDragStub.invocations.last).parameters + XCTAssertEqual(data.annotation.id, annotation.id) + XCTAssertEqual(data.context.point, context.point) + XCTAssertEqual(data.context.coordinate, context.coordinate) + + context.point.x += 1 + context.coordinate.latitude += 1 + me.handleDragEnd(context: context) + XCTAssertEqual(endDragStub.invocations.count, 1) + data = try XCTUnwrap(endDragStub.invocations.last).parameters + XCTAssertEqual(data.annotation.id, annotation.id) + XCTAssertEqual(data.context.point, context.point) + XCTAssertEqual(data.context.coordinate, context.coordinate) + } + } + + func testDoesNotUpdateDragSourceWhenNoDragged() { + let annotation = PointAnnotation(id: "point1", coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) + me.annotations = [annotation] + harness.triggerDisplayLink() + XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) + } + + func testRemovingDuplicatedAnnotations() { + let annotation1 = PointAnnotation(id: "A", point: .init(.init(latitude: 1, longitude: 1)), isSelected: false, isDraggable: false) + let annotation2 = PointAnnotation(id: "B", point: .init(.init(latitude: 2, longitude: 2)), isSelected: false, isDraggable: false) + let annotation3 = PointAnnotation(id: "A", point: .init(.init(latitude: 3, longitude: 3)), isSelected: false, isDraggable: false) + me.annotations = [annotation1, annotation2, annotation3] + + XCTAssertEqual(me.annotations, [ + annotation1, + annotation2 + ]) + } + + func testSetNewAnnotations() { + let annotation1 = PointAnnotation(id: "A", point: .init(.init(latitude: 1, longitude: 1)), isSelected: false, isDraggable: false) + let annotation2 = PointAnnotation(id: "B", point: .init(.init(latitude: 2, longitude: 2)), isSelected: false, isDraggable: false) + let annotation3 = PointAnnotation(id: "C", point: .init(.init(latitude: 3, longitude: 3)), isSelected: false, isDraggable: false) + + me.set(newAnnotations: [ + (1, annotation1), + (2, annotation2) + ]) + + XCTAssertEqual(me.annotations.map(\.id), ["A", "B"]) + + me.set(newAnnotations: [ + (1, annotation3), + (2, annotation2) + ]) + + XCTAssertEqual(me.annotations.map(\.id), ["A", "B"]) + + me.set(newAnnotations: [ + (3, annotation3), + (2, annotation2) + ]) + + XCTAssertEqual(me.annotations.map(\.id), ["C", "B"]) + } +} diff --git a/Tests/MapboxMapsTests/Annotations/AnnotationManagerTestingHarness.swift b/Tests/MapboxMapsTests/Annotations/AnnotationManagerTestingHarness.swift new file mode 100644 index 000000000000..27a493cd230b --- /dev/null +++ b/Tests/MapboxMapsTests/Annotations/AnnotationManagerTestingHarness.swift @@ -0,0 +1,28 @@ +@testable import MapboxMaps + +class AnnotationManagerTestingHarness { + let style = MockStyle() + let map = MockMapboxMap() + let mapFeatureQueryable = MockMapFeatureQueryable() + let imagesManager = MockAnnotationImagesManager() + let id = UUID().uuidString + @TestSignal + var displayLink: Signal + + func makeDeps() -> AnnotationManagerDeps { + AnnotationManagerDeps( + map: map, + style: style, + queryable: mapFeatureQueryable, + imagesManager: imagesManager, + displayLink: displayLink) + } + + func makeParams() -> AnnotationManagerParams { + AnnotationManagerParams(id: id, layerPosition: nil, clusterOptions: nil) + } + + func triggerDisplayLink() { + $displayLink.send() + } +} diff --git a/Tests/MapboxMapsTests/Annotations/AnnotationOrchestratorImplTests.swift b/Tests/MapboxMapsTests/Annotations/AnnotationOrchestratorImplTests.swift deleted file mode 100644 index 40d97c5abc10..000000000000 --- a/Tests/MapboxMapsTests/Annotations/AnnotationOrchestratorImplTests.swift +++ /dev/null @@ -1,195 +0,0 @@ -import Foundation -import XCTest -@testable import MapboxMaps - -final class AnnotationOrchestratorImplTests: XCTestCase { - var tapGestureRecognizer: MockGestureRecognizer! - var longPressGestureRecognizer: MockLongPressGestureRecognizer! - var mapFeatureQueryable: MockMapFeatureQueryable! - var style: MockStyle! - var offsetPointCalculator: OffsetPointCalculator! - var offsetLineStringCalculator: OffsetLineStringCalculator! - var offsetPolygonCalculator: OffsetPolygonCalculator! - var factory: MockAnnotationManagerFactory! - var impl: AnnotationOrchestratorImpl! - - override func setUp() { - super.setUp() - - tapGestureRecognizer = MockGestureRecognizer() - longPressGestureRecognizer = MockLongPressGestureRecognizer() - mapFeatureQueryable = MockMapFeatureQueryable() - style = MockStyle() - offsetPointCalculator = OffsetPointCalculator(mapboxMap: MockMapboxMap()) - offsetLineStringCalculator = OffsetLineStringCalculator(mapboxMap: MockMapboxMap()) - offsetPolygonCalculator = OffsetPolygonCalculator(mapboxMap: MockMapboxMap()) - factory = MockAnnotationManagerFactory() - impl = AnnotationOrchestratorImpl(factory: factory) - } - - override func tearDown() { - super.tearDown() - - tapGestureRecognizer = nil - longPressGestureRecognizer = nil - mapFeatureQueryable = nil - style = nil - offsetPointCalculator = nil - offsetLineStringCalculator = nil - offsetPolygonCalculator = nil - factory = nil - impl = nil - } - - func testMakePointAnnotationManagers() { - //given - let annotationManagerId = UUID().uuidString - let clusterOptions: ClusterOptions? = ClusterOptions() - - //when - let manager = impl.makePointAnnotationManager( - id: annotationManagerId, - layerPosition: .default, - clusterOptions: clusterOptions) - - //then - XCTAssertNotNil(impl.annotationManagersById[annotationManagerId] === manager) - XCTAssertEqual(impl.annotationManagersById.count, 1) - XCTAssertEqual(factory.makePointAnnotationManagerStub.invocations.count, 1) - - let parameters = factory.makePointAnnotationManagerStub.invocations.last?.parameters - XCTAssertEqual(parameters?.layerPosition, .default) - XCTAssertEqual(parameters?.clusterOptions, clusterOptions) - XCTAssertEqual(parameters?.id, annotationManagerId) - } - - func testMakePolygonAnnotationManagers() { - //given - let annotationManagerId = UUID().uuidString - - //when - let manager = impl.makePolygonAnnotationManager(id: annotationManagerId, layerPosition: .default) - - //then - XCTAssertNotNil(impl.annotationManagersById[annotationManagerId] === manager) - XCTAssertEqual(impl.annotationManagersById.count, 1) - XCTAssertEqual(factory.makePolygonAnnotationManagerStub.invocations.count, 1) - } - - func testMakePolylineAnnotationManagers() { - //given - let annotationManagerId = UUID().uuidString - - //when - let manager = impl.makePolylineAnnotationManager(id: annotationManagerId, layerPosition: .default) - - //then - XCTAssertNotNil(impl.annotationManagersById[annotationManagerId] === manager) - XCTAssertEqual(impl.annotationManagersById.count, 1) - XCTAssertEqual(factory.makePolylineAnnotationManagerStub.invocations.count, 1) - } - - func testMakeCircleAnnotationManagers() { - //given - let annotationManagerId = UUID().uuidString - - //when - let manager = impl.makeCircleAnnotationManager(id: annotationManagerId, layerPosition: .default) - - //then - XCTAssertNotNil(impl.annotationManagersById[annotationManagerId] === manager) - XCTAssertEqual(impl.annotationManagersById.count, 1) - XCTAssertEqual(factory.makeCircleAnnotationManagerStub.invocations.count, 1) - } - - func testRemovePointAnnotationManager() throws { - let manager = MockAnnotationManager() - factory.makePointAnnotationManagerStub.defaultReturnValue = manager - var ids = Array.random(withLength: 10, generator: { UUID().uuidString }) - - for id in ids { - _ = impl.makePointAnnotationManager(id: id, layerPosition: nil) - - // when - - let idToRemove = ids.removeFirst() - impl.removeAnnotationManager(withId: idToRemove) - - // then - XCTAssertNil(impl.annotationManagersById[idToRemove]) - } - XCTAssertEqual(manager.destroyStub.invocations.count, 10) - } - - func testRemovePolygonAnnotationManager() throws { - let manager = MockAnnotationManager() - factory.makePolygonAnnotationManagerStub.defaultReturnValue = manager - var ids = Array.random(withLength: 10, generator: { UUID().uuidString }) - for id in ids { - _ = impl.makePolygonAnnotationManager(id: id, layerPosition: nil) - - // when - let idToRemove = ids.removeFirst() - impl.removeAnnotationManager(withId: idToRemove) - - // then - XCTAssertNil(impl.annotationManagersById[idToRemove]) - } - XCTAssertEqual(manager.destroyStub.invocations.count, 10) - } - - func testRemovePolylineAnnotationManager() throws { - let manager = MockAnnotationManager() - factory.makePolylineAnnotationManagerStub.defaultReturnValue = manager - var ids = Array.random(withLength: 10, generator: { UUID().uuidString }) - for id in ids { - _ = impl.makePolylineAnnotationManager(id: id, layerPosition: nil) - - // when - let idToRemove = ids.removeFirst() - impl.removeAnnotationManager(withId: idToRemove) - - // then - XCTAssertNil(impl.annotationManagersById[idToRemove]) - } - XCTAssertEqual(manager.destroyStub.invocations.count, 10) - } - - func testRemoveCircleAnnotationManager() throws { - let manager = MockAnnotationManager() - factory.makeCircleAnnotationManagerStub.defaultReturnValue = manager - var ids = Array.random(withLength: 10, generator: { UUID().uuidString }) - for id in ids { - _ = impl.makeCircleAnnotationManager(id: id, layerPosition: nil) - - // when - let idToRemove = ids.removeFirst() - impl.removeAnnotationManager(withId: idToRemove) - - // then - XCTAssertNil(impl.annotationManagersById[idToRemove]) - } - XCTAssertEqual(manager.destroyStub.invocations.count, 10) - } - - func testManagersDestroy() { - //given - let id = "managerId" - let manager = MockAnnotationManager() - factory.makePointAnnotationManagerStub.defaultReturnValue = manager - - _ = impl.makePointAnnotationManager(id: id, layerPosition: nil, clusterOptions: nil) - - //when - impl.removeAnnotationManager(withId: id) - - //then - XCTAssertEqual(manager.destroyStub.invocations.count, 1) - } -} - -extension AnnotationOrchestratorImpl { - func makePointAnnotationManager(id: String, layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return makePointAnnotationManager(id: id, layerPosition: layerPosition, clusterOptions: nil) - } -} diff --git a/Tests/MapboxMapsTests/Annotations/AnotationOrchestratorTests.swift b/Tests/MapboxMapsTests/Annotations/AnotationOrchestratorTests.swift deleted file mode 100644 index 137087663e0e..000000000000 --- a/Tests/MapboxMapsTests/Annotations/AnotationOrchestratorTests.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation -import XCTest -@testable import MapboxMaps - -final class AnnotationOrchestratorTests: XCTestCase { - var annotationOrchestrator: AnnotationOrchestrator! - var orchestratorImpl: MockAnnotationOrchestatorImpl! - - override func setUp() { - super.setUp() - - orchestratorImpl = MockAnnotationOrchestatorImpl() - annotationOrchestrator = AnnotationOrchestrator(impl: orchestratorImpl) - } - - override func tearDown() { - super.tearDown() - - orchestratorImpl = nil - annotationOrchestrator = nil - } - - func testPointAnnotationnManagerInit() throws { - //given - let id = "managerId" - let layerPosition: LayerPosition? = .at(38) - let clusterOptions: ClusterOptions? = .init() - - //when - _ = annotationOrchestrator.makePointAnnotationManager(id: id, layerPosition: layerPosition, clusterOptions: clusterOptions) - - //then - XCTAssertEqual(orchestratorImpl.makePointAnnotationManagerStub.invocations.count, 1) - let param = try XCTUnwrap(orchestratorImpl.makePointAnnotationManagerStub.invocations.first?.parameters) - XCTAssertEqual(param.id, id) - XCTAssertEqual(param.layerPosition, layerPosition) - XCTAssertEqual(param.clusterOptions, clusterOptions) - } - - func testPolygonAnnotationManagerInit() throws { - //given - let id = "managerId" - let layerPosition: LayerPosition? = .at(81) - - //when - _ = annotationOrchestrator.makePolygonAnnotationManager(id: id, layerPosition: layerPosition) as AnnotationManagerInternal - - //then - XCTAssertEqual(orchestratorImpl.makePolygonAnnotationManagerStub.invocations.count, 1) - let param = try XCTUnwrap(orchestratorImpl.makePolygonAnnotationManagerStub.invocations.first?.parameters) - XCTAssertEqual(param.id, id) - XCTAssertEqual(param.layerPosition, layerPosition) - } - - func testPolylineAnnotationManagerInit() throws { - //given - let id = "managerId" - let layerPosition: LayerPosition? = .at(48) - - //when - _ = annotationOrchestrator.makePolylineAnnotationManager(id: id, layerPosition: layerPosition) - - //then - XCTAssertEqual(orchestratorImpl.makePolylineAnnotationManagerStub.invocations.count, 1) - let param = try XCTUnwrap(orchestratorImpl.makePolylineAnnotationManagerStub.invocations.first?.parameters) - XCTAssertEqual(param.id, id) - XCTAssertEqual(param.layerPosition, layerPosition) - } - - func testCircleAnnotationManagerInit() throws { - //given - let id = "managerId" - let layerPosition: LayerPosition? = .at(91) - - //when - _ = annotationOrchestrator.makeCircleAnnotationManager(id: id, layerPosition: layerPosition) - - //then - XCTAssertEqual(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.count, 1) - - let param = try XCTUnwrap(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.first?.parameters) - XCTAssertEqual(param.id, id) - XCTAssertEqual(param.layerPosition, layerPosition) - } -} diff --git a/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationIntegrationTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationIntegrationTests.swift index b8ae2adda7ee..3cd1114626f4 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationIntegrationTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationIntegrationTests.swift @@ -24,7 +24,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { } func testSourceAndLayerRemovedUponDestroy() { - manager.destroy() + manager.impl.destroy() XCTAssertFalse(mapView.mapboxMap.allLayerIdentifiers.map { $0.id }.contains(manager.layerId)) XCTAssertFalse(mapView.mapboxMap.allSourceIdentifiers.map { $0.id }.contains(manager.sourceId)) @@ -68,7 +68,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.circleEmissiveStrength, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) if case .constant(let actualValue) = layer.circleEmissiveStrength { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -82,7 +82,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleEmissiveStrength, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-emissive-strength").value as! NSNumber).doubleValue)) } @@ -94,7 +94,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.circlePitchAlignment, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) if case .constant(let actualValue) = layer.circlePitchAlignment { XCTAssertEqual(actualValue, value) @@ -108,7 +108,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circlePitchAlignment, .constant(CirclePitchAlignment(rawValue: StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-pitch-alignment").value as! String))) } @@ -120,7 +120,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.circlePitchScale, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) if case .constant(let actualValue) = layer.circlePitchScale { XCTAssertEqual(actualValue, value) @@ -134,7 +134,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circlePitchScale, .constant(CirclePitchScale(rawValue: StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-pitch-scale").value as! String))) } @@ -146,7 +146,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.circleTranslate, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) if case .constant(let actualValue) = layer.circleTranslate { for (actual, expected) in zip(actualValue, value) { @@ -162,7 +162,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleTranslate, .constant(StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-translate").value as! [Double])) } @@ -174,7 +174,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.circleTranslateAnchor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) if case .constant(let actualValue) = layer.circleTranslateAnchor { XCTAssertEqual(actualValue, value) @@ -188,7 +188,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleTranslateAnchor, .constant(CircleTranslateAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-translate-anchor").value as! String))) } @@ -200,7 +200,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.slot, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) let actualValue = layer.slot?.rawValue ?? "" XCTAssertEqual(actualValue, value) @@ -211,7 +211,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.slot, nil) } @@ -226,7 +226,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleSortKey, .expression(Exp(.number) { Exp(.get) { @@ -247,7 +247,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleSortKey, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-sort-key").value as! NSNumber).doubleValue)) } @@ -262,7 +262,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleBlur, .expression(Exp(.number) { Exp(.get) { @@ -283,7 +283,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleBlur, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-blur").value as! NSNumber).doubleValue)) } @@ -298,7 +298,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleColor, .expression(Exp(.toColor) { Exp(.get) { @@ -319,7 +319,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-color").value as! [Any], options: [])))) } @@ -334,7 +334,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleOpacity, .expression(Exp(.number) { Exp(.get) { @@ -355,7 +355,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-opacity").value as! NSNumber).doubleValue)) } @@ -370,7 +370,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleRadius, .expression(Exp(.number) { Exp(.get) { @@ -391,7 +391,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleRadius, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-radius").value as! NSNumber).doubleValue)) } @@ -406,7 +406,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleStrokeColor, .expression(Exp(.toColor) { Exp(.get) { @@ -427,7 +427,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleStrokeColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-stroke-color").value as! [Any], options: [])))) } @@ -442,7 +442,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleStrokeOpacity, .expression(Exp(.number) { Exp(.get) { @@ -463,7 +463,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleStrokeOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-stroke-opacity").value as! NSNumber).doubleValue)) } @@ -478,7 +478,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleStrokeWidth, .expression(Exp(.number) { Exp(.get) { @@ -499,7 +499,7 @@ final class CircleAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: CircleLayer.self) XCTAssertEqual(layer.circleStrokeWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-stroke-width").value as! NSNumber).doubleValue)) } diff --git a/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationManagerTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationManagerTests.swift index 48d504b0a498..e342c9068afa 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationManagerTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/CircleAnnotationManagerTests.swift @@ -4,28 +4,18 @@ import XCTest final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDelegate { var manager: CircleAnnotationManager! - var style: MockStyle! - var id = UUID().uuidString + var harness: AnnotationManagerTestingHarness! var annotations = [CircleAnnotation]() var expectation: XCTestExpectation? var delegateAnnotations: [Annotation]? - var offsetCalculator: OffsetPointCalculator! - var mapboxMap: MockMapboxMap! - @TestSignal var displayLink: Signal override func setUp() { super.setUp() - style = MockStyle() - mapboxMap = MockMapboxMap() - offsetCalculator = OffsetPointCalculator(mapboxMap: mapboxMap) + harness = AnnotationManagerTestingHarness() manager = CircleAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) + params: harness.makeParams(), + deps: harness.makeDeps()) for _ in 0...10 { let annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) @@ -34,209 +24,11 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg } override func tearDown() { - style = nil - expectation = nil - delegateAnnotations = nil - mapboxMap = nil - offsetCalculator = nil + harness = nil manager = nil - super.tearDown() } - func testSourceSetup() { - style.addSourceStub.reset() - - _ = CircleAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.type, SourceType.geoJson) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.id, manager.id) - } - - func testAddLayer() throws { - style.addSourceStub.reset() - let initializedManager = CircleAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerWithPropertiesStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.type, LayerType.circle) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.id, initializedManager.id) - let addedLayer = try XCTUnwrap(style.addPersistentLayerStub.invocations.last?.parameters.layer as? CircleLayer) - XCTAssertEqual(addedLayer.source, initializedManager.sourceId) - XCTAssertNil(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition) - } - - func testAddManagerWithDuplicateId() { - var annotations2 = [CircleAnnotation]() - for _ in 0...50 { - let annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations2.append(annotation) - } - - manager.annotations = annotations - let manager2 = CircleAnnotationManager( - id: manager.id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - manager2.annotations = annotations2 - - XCTAssertEqual(manager.annotations.count, 11) - XCTAssertEqual(manager2.annotations.count, 51) - } - - func testLayerPositionPassedCorrectly() { - let manager3 = CircleAnnotationManager( - id: id, - style: style, - layerPosition: LayerPosition.at(4), - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - manager3.annotations = annotations - - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition, LayerPosition.at(4)) - } - - func testDestroy() { - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testDestroyManagerWithDraggedAnnotations() { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.isDraggable = true - manager.annotations = [annotation] - // adds drag source/layer - _ = manager.handleDragBegin(with: annotation.id, context: .zero) - - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id, id + "_drag"]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id, id + "_drag"]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testSyncSourceAndLayer() { - manager.annotations = annotations - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - } - - func testDoNotSyncSourceAndLayerWhenNotNeeded() { - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 0) - } - - func testFeatureCollectionPassedtoGeoJSON() throws { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - let annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - let expectedFeatures = annotations.map(\.feature) - - manager.annotations = annotations - $displayLink.send() - - var invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, expectedFeatures) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - - do { - let annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations.append(annotation) - - manager.annotations = annotations - $displayLink.send() - - invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, [annotation].map(\.feature)) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - } - } - - @available(*, deprecated) - func testHandleTap() throws { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - let annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - var taps = [MapContentGestureContext]() - annotations[0].tapHandler = { context in - taps.append(context) - return true - } - annotations[1].tapHandler = { _ in - return false // skips handling - } - manager.delegate = self - - manager.annotations = annotations - - // first annotation, handles tap - let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) - var handled = manager.handleTap(layerId: "layerId", feature: annotations[0].feature, context: context) - - var result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[0].id) - XCTAssertEqual(handled, true) - - XCTAssertEqual(taps.count, 1) - XCTAssertEqual(taps.first?.point, context.point) - XCTAssertEqual(taps.first?.coordinate, context.coordinate) - - // second annotation, skips handling tap - delegateAnnotations = nil - handled = manager.handleTap(layerId: "layerId", feature: annotations[1].feature, context: context) - - result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[1].id) - XCTAssertEqual(handled, false) - - // invalid id - delegateAnnotations = nil - let invalidFeature = Feature(geometry: nil) - handled = manager.handleTap(layerId: "layerId", feature: invalidFeature, context: context) - - XCTAssertNil(delegateAnnotations) - XCTAssertEqual(handled, false) - XCTAssertEqual(taps.count, 1) - } - func testInitialCircleEmissiveStrength() { let initialValue = manager.circleEmissiveStrength XCTAssertNil(initialValue) @@ -246,67 +38,22 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg let value = 50000.0 manager.circleEmissiveStrength = value XCTAssertEqual(manager.circleEmissiveStrength, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-emissive-strength"] as! Double, value) - } - - func testCircleEmissiveStrengthAnnotationPropertiesAddedWithoutDuplicate() { - let newCircleEmissiveStrengthProperty = 50000.0 - let secondCircleEmissiveStrengthProperty = 50000.0 - - manager.circleEmissiveStrength = newCircleEmissiveStrengthProperty - $displayLink.send() - manager.circleEmissiveStrength = secondCircleEmissiveStrengthProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-emissive-strength"] as! Double, secondCircleEmissiveStrengthProperty) - } - - func testNewCircleEmissiveStrengthPropertyMergedWithAnnotationProperties() { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.circleSortKey = 0.0 - annotation.circleBlur = 0.0 - annotation.circleColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleOpacity = 0.5 - annotation.circleRadius = 50000.0 - annotation.circleStrokeColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleStrokeOpacity = 0.5 - annotation.circleStrokeWidth = 50000.0 - annotations.append(annotation) - } - let newCircleEmissiveStrengthProperty = 50000.0 - - manager.annotations = annotations - manager.circleEmissiveStrength = newCircleEmissiveStrengthProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-emissive-strength"]) + XCTAssertEqual(manager.impl.layerProperties["circle-emissive-strength"] as! Double, value) } func testSetToNilCircleEmissiveStrength() { let newCircleEmissiveStrengthProperty = 50000.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-emissive-strength").value as! Double manager.circleEmissiveStrength = newCircleEmissiveStrengthProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-emissive-strength"]) + XCTAssertNotNil(manager.impl.layerProperties["circle-emissive-strength"]) + harness.triggerDisplayLink() manager.circleEmissiveStrength = nil - $displayLink.send() XCTAssertNil(manager.circleEmissiveStrength) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-emissive-strength"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-emissive-strength"] as! Double, defaultValue) } - func testInitialCirclePitchAlignment() { let initialValue = manager.circlePitchAlignment XCTAssertNil(initialValue) @@ -316,67 +63,22 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg let value = CirclePitchAlignment.testConstantValue() manager.circlePitchAlignment = value XCTAssertEqual(manager.circlePitchAlignment, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-alignment"] as! String, value.rawValue) - } - - func testCirclePitchAlignmentAnnotationPropertiesAddedWithoutDuplicate() { - let newCirclePitchAlignmentProperty = CirclePitchAlignment.testConstantValue() - let secondCirclePitchAlignmentProperty = CirclePitchAlignment.testConstantValue() - - manager.circlePitchAlignment = newCirclePitchAlignmentProperty - $displayLink.send() - manager.circlePitchAlignment = secondCirclePitchAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-alignment"] as! String, secondCirclePitchAlignmentProperty.rawValue) - } - - func testNewCirclePitchAlignmentPropertyMergedWithAnnotationProperties() { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.circleSortKey = 0.0 - annotation.circleBlur = 0.0 - annotation.circleColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleOpacity = 0.5 - annotation.circleRadius = 50000.0 - annotation.circleStrokeColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleStrokeOpacity = 0.5 - annotation.circleStrokeWidth = 50000.0 - annotations.append(annotation) - } - let newCirclePitchAlignmentProperty = CirclePitchAlignment.testConstantValue() - - manager.annotations = annotations - manager.circlePitchAlignment = newCirclePitchAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-alignment"]) + XCTAssertEqual(manager.impl.layerProperties["circle-pitch-alignment"] as! String, value.rawValue) } func testSetToNilCirclePitchAlignment() { let newCirclePitchAlignmentProperty = CirclePitchAlignment.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-pitch-alignment").value as! String manager.circlePitchAlignment = newCirclePitchAlignmentProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-alignment"]) + XCTAssertNotNil(manager.impl.layerProperties["circle-pitch-alignment"]) + harness.triggerDisplayLink() manager.circlePitchAlignment = nil - $displayLink.send() XCTAssertNil(manager.circlePitchAlignment) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-alignment"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-alignment"] as! String, defaultValue) } - func testInitialCirclePitchScale() { let initialValue = manager.circlePitchScale XCTAssertNil(initialValue) @@ -386,67 +88,22 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg let value = CirclePitchScale.testConstantValue() manager.circlePitchScale = value XCTAssertEqual(manager.circlePitchScale, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-scale"] as! String, value.rawValue) - } - - func testCirclePitchScaleAnnotationPropertiesAddedWithoutDuplicate() { - let newCirclePitchScaleProperty = CirclePitchScale.testConstantValue() - let secondCirclePitchScaleProperty = CirclePitchScale.testConstantValue() - - manager.circlePitchScale = newCirclePitchScaleProperty - $displayLink.send() - manager.circlePitchScale = secondCirclePitchScaleProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-scale"] as! String, secondCirclePitchScaleProperty.rawValue) - } - - func testNewCirclePitchScalePropertyMergedWithAnnotationProperties() { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.circleSortKey = 0.0 - annotation.circleBlur = 0.0 - annotation.circleColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleOpacity = 0.5 - annotation.circleRadius = 50000.0 - annotation.circleStrokeColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleStrokeOpacity = 0.5 - annotation.circleStrokeWidth = 50000.0 - annotations.append(annotation) - } - let newCirclePitchScaleProperty = CirclePitchScale.testConstantValue() - - manager.annotations = annotations - manager.circlePitchScale = newCirclePitchScaleProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-scale"]) + XCTAssertEqual(manager.impl.layerProperties["circle-pitch-scale"] as! String, value.rawValue) } func testSetToNilCirclePitchScale() { let newCirclePitchScaleProperty = CirclePitchScale.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-pitch-scale").value as! String manager.circlePitchScale = newCirclePitchScaleProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-scale"]) + XCTAssertNotNil(manager.impl.layerProperties["circle-pitch-scale"]) + harness.triggerDisplayLink() manager.circlePitchScale = nil - $displayLink.send() XCTAssertNil(manager.circlePitchScale) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-scale"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-pitch-scale"] as! String, defaultValue) } - func testInitialCircleTranslate() { let initialValue = manager.circleTranslate XCTAssertNil(initialValue) @@ -456,67 +113,22 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg let value = [0.0, 0.0] manager.circleTranslate = value XCTAssertEqual(manager.circleTranslate, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate"] as! [Double], value) - } - - func testCircleTranslateAnnotationPropertiesAddedWithoutDuplicate() { - let newCircleTranslateProperty = [0.0, 0.0] - let secondCircleTranslateProperty = [0.0, 0.0] - - manager.circleTranslate = newCircleTranslateProperty - $displayLink.send() - manager.circleTranslate = secondCircleTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate"] as! [Double], secondCircleTranslateProperty) - } - - func testNewCircleTranslatePropertyMergedWithAnnotationProperties() { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.circleSortKey = 0.0 - annotation.circleBlur = 0.0 - annotation.circleColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleOpacity = 0.5 - annotation.circleRadius = 50000.0 - annotation.circleStrokeColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleStrokeOpacity = 0.5 - annotation.circleStrokeWidth = 50000.0 - annotations.append(annotation) - } - let newCircleTranslateProperty = [0.0, 0.0] - - manager.annotations = annotations - manager.circleTranslate = newCircleTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate"]) + XCTAssertEqual(manager.impl.layerProperties["circle-translate"] as! [Double], value) } func testSetToNilCircleTranslate() { let newCircleTranslateProperty = [0.0, 0.0] let defaultValue = StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-translate").value as! [Double] manager.circleTranslate = newCircleTranslateProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate"]) + XCTAssertNotNil(manager.impl.layerProperties["circle-translate"]) + harness.triggerDisplayLink() manager.circleTranslate = nil - $displayLink.send() XCTAssertNil(manager.circleTranslate) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate"] as! [Double], defaultValue) } - func testInitialCircleTranslateAnchor() { let initialValue = manager.circleTranslateAnchor XCTAssertNil(initialValue) @@ -526,67 +138,22 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg let value = CircleTranslateAnchor.testConstantValue() manager.circleTranslateAnchor = value XCTAssertEqual(manager.circleTranslateAnchor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate-anchor"] as! String, value.rawValue) - } - - func testCircleTranslateAnchorAnnotationPropertiesAddedWithoutDuplicate() { - let newCircleTranslateAnchorProperty = CircleTranslateAnchor.testConstantValue() - let secondCircleTranslateAnchorProperty = CircleTranslateAnchor.testConstantValue() - - manager.circleTranslateAnchor = newCircleTranslateAnchorProperty - $displayLink.send() - manager.circleTranslateAnchor = secondCircleTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate-anchor"] as! String, secondCircleTranslateAnchorProperty.rawValue) - } - - func testNewCircleTranslateAnchorPropertyMergedWithAnnotationProperties() { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.circleSortKey = 0.0 - annotation.circleBlur = 0.0 - annotation.circleColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleOpacity = 0.5 - annotation.circleRadius = 50000.0 - annotation.circleStrokeColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleStrokeOpacity = 0.5 - annotation.circleStrokeWidth = 50000.0 - annotations.append(annotation) - } - let newCircleTranslateAnchorProperty = CircleTranslateAnchor.testConstantValue() - - manager.annotations = annotations - manager.circleTranslateAnchor = newCircleTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate-anchor"]) + XCTAssertEqual(manager.impl.layerProperties["circle-translate-anchor"] as! String, value.rawValue) } func testSetToNilCircleTranslateAnchor() { let newCircleTranslateAnchorProperty = CircleTranslateAnchor.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .circle, property: "circle-translate-anchor").value as! String manager.circleTranslateAnchor = newCircleTranslateAnchorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate-anchor"]) + XCTAssertNotNil(manager.impl.layerProperties["circle-translate-anchor"]) + harness.triggerDisplayLink() manager.circleTranslateAnchor = nil - $displayLink.send() XCTAssertNil(manager.circleTranslateAnchor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate-anchor"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["circle-translate-anchor"] as! String, defaultValue) } - func testInitialSlot() { let initialValue = manager.slot XCTAssertNil(initialValue) @@ -596,65 +163,21 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg let value = UUID().uuidString manager.slot = value XCTAssertEqual(manager.slot, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, value) - } - - func testSlotAnnotationPropertiesAddedWithoutDuplicate() { - let newSlotProperty = UUID().uuidString - let secondSlotProperty = UUID().uuidString - - manager.slot = newSlotProperty - $displayLink.send() - manager.slot = secondSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, secondSlotProperty) - } - - func testNewSlotPropertyMergedWithAnnotationProperties() { - var annotations = [CircleAnnotation]() - for _ in 0...5 { - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.circleSortKey = 0.0 - annotation.circleBlur = 0.0 - annotation.circleColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleOpacity = 0.5 - annotation.circleRadius = 50000.0 - annotation.circleStrokeColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.circleStrokeOpacity = 0.5 - annotation.circleStrokeWidth = 50000.0 - annotations.append(annotation) - } - let newSlotProperty = UUID().uuidString - - manager.annotations = annotations - manager.slot = newSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertEqual(manager.impl.layerProperties["slot"] as! String, value) } func testSetToNilSlot() { let newSlotProperty = UUID().uuidString let defaultValue = StyleManager.layerPropertyDefaultValue(for: .circle, property: "slot").value as! String manager.slot = newSlotProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertNotNil(manager.impl.layerProperties["slot"]) + harness.triggerDisplayLink() manager.slot = nil - $displayLink.send() XCTAssertNil(manager.slot) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) } func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) { @@ -663,211 +186,6 @@ final class CircleAnnotationManagerTests: XCTestCase, AnnotationInteractionDeleg expectation = nil } - func testGetAnnotations() { - let annotations = Array.random(withLength: 10) { - CircleAnnotation(centerCoordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) - } - manager.annotations = annotations - - // Dragged annotation will be added to internal list of dragged annotations. - let annotationToDrag = annotations.randomElement()! - _ = manager.handleDragBegin(with: annotationToDrag.id, context: .zero) - XCTAssertTrue(manager.annotations.contains(where: { $0.id == annotationToDrag.id })) - } - - func testHandleDragBeginIsDraggableFalse() throws { - manager.annotations = [ - CircleAnnotation(id: "circle1", centerCoordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - ] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "circle1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 0) - } - func testHandleDragBeginInvalidFeatureId() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "not-a-feature", context: .zero) - - XCTAssertTrue(style.addSourceStub.invocations.isEmpty) - XCTAssertTrue(style.addPersistentLayerStub.invocations.isEmpty) - } - - func testDrag() throws { - let annotation = CircleAnnotation(id: "circle1", centerCoordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) - manager.annotations = [annotation] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - _ = manager.handleDragBegin(with: "circle1", context: .zero) - - let addSourceParameters = try XCTUnwrap(style.addSourceStub.invocations.last).parameters - let addLayerParameters = try XCTUnwrap(style.addPersistentLayerStub.invocations.last).parameters - - let addedLayer = try XCTUnwrap(addLayerParameters.layer as? CircleLayer) - XCTAssertEqual(addedLayer.source, addSourceParameters.source.id) - XCTAssertEqual(addLayerParameters.layerPosition, .above(manager.id)) - XCTAssertEqual(addedLayer.id, manager.id + "_drag") - - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 1) - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.last?.parameters.id, "\(manager.id)_drag") - - _ = manager.handleDragBegin(with: "circle1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 1) - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 0, longitude: 0) - mapboxMap.cameraState.zoom = 1 - - manager.handleDragChange(with: .zero, context: .zero) - - $displayLink.send() - - let updateSourceParameters = try XCTUnwrap(style.updateGeoJSONSourceStub.invocations.last).parameters - XCTAssertTrue(updateSourceParameters.id == addSourceParameters.source.id) - if case .featureCollection(let collection) = updateSourceParameters.geojson { - XCTAssertTrue(collection.features.contains(where: { $0.identifier?.rawValue as? String == annotation.id })) - } else { - XCTFail("GeoJSONObject should be a feature collection") - } - } - - func testDragHandlers() throws { - struct GestureData { - var annotation: CircleAnnotation - var context: MapContentGestureContext - } - - var annotation = CircleAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.isDraggable = true - - let beginDragStub = Stub(defaultReturnValue: false) - let changeDragStub = Stub() - let endDragStub = Stub() - annotation.dragBeginHandler = { annotation, context in - beginDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragChangeHandler = { annotation, context in - changeDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragEndHandler = { annotation, context in - endDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - manager.annotations = [annotation] - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 23.5432356, longitude: -12.5326744) - mapboxMap.cameraState.zoom = 1 - - var context = MapContentGestureContext(point: CGPoint(x: 0, y: 1), coordinate: .init(latitude: 2, longitude: 3)) - - // test it twice to cover the case when annotation was already on drag layer. - for _ in 0...1 { - beginDragStub.reset() - changeDragStub.reset() - endDragStub.reset() - - // skipped gesture - beginDragStub.defaultReturnValue = false - var res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 1) - XCTAssertEqual(res, false) - var data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - manager.handleDragEnd(context: context) - XCTAssertEqual(changeDragStub.invocations.count, 0) - XCTAssertEqual(endDragStub.invocations.count, 0) - - // handled gesture - context.point.x += 1 - context.coordinate.latitude += 1 - beginDragStub.defaultReturnValue = true - res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 2) - XCTAssertEqual(res, true) - data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - XCTAssertEqual(changeDragStub.invocations.count, 1) - data = try XCTUnwrap(changeDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragEnd(context: context) - XCTAssertEqual(endDragStub.invocations.count, 1) - data = try XCTUnwrap(endDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - } - } - - func testDoesNotUpdateDragSourceWhenNoDragged() { - let annotation = CircleAnnotation(id: "circle1", centerCoordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) - manager.annotations = [annotation] - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - } - - func testRemovingDuplicatedAnnotations() { - let annotation1 = CircleAnnotation(id: "A", point: .init(.init(latitude: 1, longitude: 1)), isSelected: false, isDraggable: false) - let annotation2 = CircleAnnotation(id: "B", point: .init(.init(latitude: 2, longitude: 2)), isSelected: false, isDraggable: false) - let annotation3 = CircleAnnotation(id: "A", point: .init(.init(latitude: 3, longitude: 3)), isSelected: false, isDraggable: false) - manager.annotations = [annotation1, annotation2, annotation3] - - XCTAssertEqual(manager.annotations, [ - annotation1, - annotation2 - ]) - } - - func testSetNewAnnotations() { - let annotation1 = CircleAnnotation(id: "A", point: .init(.init(latitude: 1, longitude: 1)), isSelected: false, isDraggable: false) - let annotation2 = CircleAnnotation(id: "B", point: .init(.init(latitude: 2, longitude: 2)), isSelected: false, isDraggable: false) - let annotation3 = CircleAnnotation(id: "C", point: .init(.init(latitude: 3, longitude: 3)), isSelected: false, isDraggable: false) - - manager.set(newAnnotations: [ - (1, annotation1), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (1, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (3, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["C", "B"]) - } } // End of generated file diff --git a/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationIntegrationTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationIntegrationTests.swift index 9d433cad8119..4be2d82ecf39 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationIntegrationTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationIntegrationTests.swift @@ -24,7 +24,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { } func testSourceAndLayerRemovedUponDestroy() { - manager.destroy() + manager.impl.destroy() XCTAssertFalse(mapView.mapboxMap.allLayerIdentifiers.map { $0.id }.contains(manager.layerId)) XCTAssertFalse(mapView.mapboxMap.allSourceIdentifiers.map { $0.id }.contains(manager.sourceId)) @@ -68,7 +68,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconAllowOverlap, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconAllowOverlap { XCTAssertEqual(actualValue, value) @@ -82,7 +82,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconAllowOverlap, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-allow-overlap").value as! NSNumber).boolValue)) } @@ -94,7 +94,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconIgnorePlacement, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconIgnorePlacement { XCTAssertEqual(actualValue, value) @@ -108,7 +108,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconIgnorePlacement, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-ignore-placement").value as! NSNumber).boolValue)) } @@ -120,7 +120,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconKeepUpright, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconKeepUpright { XCTAssertEqual(actualValue, value) @@ -134,7 +134,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconKeepUpright, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-keep-upright").value as! NSNumber).boolValue)) } @@ -146,7 +146,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconOptional, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconOptional { XCTAssertEqual(actualValue, value) @@ -160,7 +160,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOptional, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-optional").value as! NSNumber).boolValue)) } @@ -172,7 +172,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconPadding, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconPadding { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -186,7 +186,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconPadding, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-padding").value as! NSNumber).doubleValue)) } @@ -198,7 +198,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconPitchAlignment, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconPitchAlignment { XCTAssertEqual(actualValue, value) @@ -212,7 +212,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconPitchAlignment, .constant(IconPitchAlignment(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-pitch-alignment").value as! String))) } @@ -224,7 +224,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconRotationAlignment, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconRotationAlignment { XCTAssertEqual(actualValue, value) @@ -238,7 +238,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconRotationAlignment, .constant(IconRotationAlignment(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-rotation-alignment").value as! String))) } @@ -250,7 +250,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.symbolAvoidEdges, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.symbolAvoidEdges { XCTAssertEqual(actualValue, value) @@ -264,7 +264,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolAvoidEdges, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-avoid-edges").value as! NSNumber).boolValue)) } @@ -276,7 +276,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.symbolPlacement, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.symbolPlacement { XCTAssertEqual(actualValue, value) @@ -290,7 +290,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolPlacement, .constant(SymbolPlacement(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-placement").value as! String))) } @@ -302,7 +302,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.symbolSpacing, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.symbolSpacing { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -316,7 +316,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolSpacing, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-spacing").value as! NSNumber).doubleValue)) } @@ -328,7 +328,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.symbolZElevate, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.symbolZElevate { XCTAssertEqual(actualValue, value) @@ -342,7 +342,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolZElevate, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-z-elevate").value as! NSNumber).boolValue)) } @@ -354,7 +354,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.symbolZOrder, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.symbolZOrder { XCTAssertEqual(actualValue, value) @@ -368,7 +368,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolZOrder, .constant(SymbolZOrder(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-z-order").value as! String))) } @@ -380,7 +380,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textAllowOverlap, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textAllowOverlap { XCTAssertEqual(actualValue, value) @@ -394,7 +394,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textAllowOverlap, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-allow-overlap").value as! NSNumber).boolValue)) } @@ -406,7 +406,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textFont, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textFont { XCTAssertEqual(actualValue, value) @@ -420,7 +420,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textFont, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-font").value as! [String])) } @@ -432,7 +432,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textIgnorePlacement, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textIgnorePlacement { XCTAssertEqual(actualValue, value) @@ -446,7 +446,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textIgnorePlacement, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-ignore-placement").value as! NSNumber).boolValue)) } @@ -458,7 +458,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textKeepUpright, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textKeepUpright { XCTAssertEqual(actualValue, value) @@ -472,7 +472,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textKeepUpright, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-keep-upright").value as! NSNumber).boolValue)) } @@ -484,7 +484,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textMaxAngle, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textMaxAngle { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -498,7 +498,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textMaxAngle, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-max-angle").value as! NSNumber).doubleValue)) } @@ -510,7 +510,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textOptional, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textOptional { XCTAssertEqual(actualValue, value) @@ -524,7 +524,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOptional, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-optional").value as! NSNumber).boolValue)) } @@ -536,7 +536,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textPadding, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textPadding { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -550,7 +550,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textPadding, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-padding").value as! NSNumber).doubleValue)) } @@ -562,7 +562,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textPitchAlignment, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textPitchAlignment { XCTAssertEqual(actualValue, value) @@ -576,7 +576,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textPitchAlignment, .constant(TextPitchAlignment(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-pitch-alignment").value as! String))) } @@ -588,7 +588,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textRotationAlignment, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textRotationAlignment { XCTAssertEqual(actualValue, value) @@ -602,7 +602,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textRotationAlignment, .constant(TextRotationAlignment(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-rotation-alignment").value as! String))) } @@ -614,7 +614,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textVariableAnchor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textVariableAnchor { XCTAssertEqual(actualValue, value) @@ -628,7 +628,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textVariableAnchor, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-variable-anchor").value as! [TextAnchor])) } @@ -640,7 +640,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textWritingMode, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textWritingMode { XCTAssertEqual(actualValue, value) @@ -654,7 +654,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textWritingMode, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-writing-mode").value as! [TextWritingMode])) } @@ -666,7 +666,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconColorSaturation, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconColorSaturation { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -680,7 +680,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconColorSaturation, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-color-saturation").value as! NSNumber).doubleValue)) } @@ -692,7 +692,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconTranslate, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconTranslate { for (actual, expected) in zip(actualValue, value) { @@ -708,7 +708,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconTranslate, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-translate").value as! [Double])) } @@ -720,7 +720,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.iconTranslateAnchor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.iconTranslateAnchor { XCTAssertEqual(actualValue, value) @@ -734,7 +734,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconTranslateAnchor, .constant(IconTranslateAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-translate-anchor").value as! String))) } @@ -746,7 +746,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textTranslate, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textTranslate { for (actual, expected) in zip(actualValue, value) { @@ -762,7 +762,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textTranslate, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-translate").value as! [Double])) } @@ -774,7 +774,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.textTranslateAnchor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) if case .constant(let actualValue) = layer.textTranslateAnchor { XCTAssertEqual(actualValue, value) @@ -788,7 +788,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textTranslateAnchor, .constant(TextTranslateAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-translate-anchor").value as! String))) } @@ -800,7 +800,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.slot, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) let actualValue = layer.slot?.rawValue ?? "" XCTAssertEqual(actualValue, value) @@ -811,7 +811,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.slot, nil) } @@ -826,7 +826,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconAnchor, .expression(Exp(.toString) { Exp(.get) { @@ -847,7 +847,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconAnchor, .constant(IconAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-anchor").value as! String))) } @@ -862,7 +862,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconImage, .expression(Exp(.image) { Exp(.get) { @@ -883,7 +883,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconImage, .constant(.name(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-image").value as! String))) } @@ -898,7 +898,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOffset, .expression(Exp(.array) { "number" @@ -921,7 +921,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOffset, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-offset").value as! [Double])) } @@ -936,7 +936,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconRotate, .expression(Exp(.number) { Exp(.get) { @@ -957,7 +957,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconRotate, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-rotate").value as! NSNumber).doubleValue)) } @@ -972,7 +972,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconSize, .expression(Exp(.number) { Exp(.get) { @@ -993,7 +993,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconSize, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-size").value as! NSNumber).doubleValue)) } @@ -1008,7 +1008,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconTextFit, .expression(Exp(.toString) { Exp(.get) { @@ -1029,7 +1029,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconTextFit, .constant(IconTextFit(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-text-fit").value as! String))) } @@ -1044,7 +1044,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconTextFitPadding, .expression(Exp(.array) { "number" @@ -1067,7 +1067,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconTextFitPadding, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-text-fit-padding").value as! [Double])) } @@ -1082,7 +1082,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolSortKey, .expression(Exp(.number) { Exp(.get) { @@ -1103,7 +1103,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.symbolSortKey, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-sort-key").value as! NSNumber).doubleValue)) } @@ -1118,7 +1118,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textAnchor, .expression(Exp(.toString) { Exp(.get) { @@ -1139,7 +1139,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textAnchor, .constant(TextAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-anchor").value as! String))) } @@ -1154,7 +1154,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textField, .expression(Exp(.format) { Exp(.get) { @@ -1176,7 +1176,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textField, .expression(Exp(.format) { "" @@ -1194,7 +1194,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textJustify, .expression(Exp(.toString) { Exp(.get) { @@ -1215,7 +1215,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textJustify, .constant(TextJustify(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-justify").value as! String))) } @@ -1230,7 +1230,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textLetterSpacing, .expression(Exp(.number) { Exp(.get) { @@ -1251,7 +1251,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textLetterSpacing, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-letter-spacing").value as! NSNumber).doubleValue)) } @@ -1266,7 +1266,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textLineHeight, .expression(Exp(.number) { Exp(.get) { @@ -1287,7 +1287,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textLineHeight, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-line-height").value as! NSNumber).doubleValue)) } @@ -1302,7 +1302,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textMaxWidth, .expression(Exp(.number) { Exp(.get) { @@ -1323,7 +1323,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textMaxWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-max-width").value as! NSNumber).doubleValue)) } @@ -1338,7 +1338,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOffset, .expression(Exp(.array) { "number" @@ -1361,7 +1361,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOffset, .constant(StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-offset").value as! [Double])) } @@ -1376,7 +1376,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textRadialOffset, .expression(Exp(.number) { Exp(.get) { @@ -1397,7 +1397,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textRadialOffset, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-radial-offset").value as! NSNumber).doubleValue)) } @@ -1412,7 +1412,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textRotate, .expression(Exp(.number) { Exp(.get) { @@ -1433,7 +1433,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textRotate, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-rotate").value as! NSNumber).doubleValue)) } @@ -1448,7 +1448,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textSize, .expression(Exp(.number) { Exp(.get) { @@ -1469,7 +1469,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textSize, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-size").value as! NSNumber).doubleValue)) } @@ -1484,7 +1484,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textTransform, .expression(Exp(.toString) { Exp(.get) { @@ -1505,7 +1505,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textTransform, .constant(TextTransform(rawValue: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-transform").value as! String))) } @@ -1520,7 +1520,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconColor, .expression(Exp(.toColor) { Exp(.get) { @@ -1541,7 +1541,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-color").value as! [Any], options: [])))) } @@ -1556,7 +1556,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconEmissiveStrength, .expression(Exp(.number) { Exp(.get) { @@ -1577,7 +1577,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconEmissiveStrength, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-emissive-strength").value as! NSNumber).doubleValue)) } @@ -1592,7 +1592,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconHaloBlur, .expression(Exp(.number) { Exp(.get) { @@ -1613,7 +1613,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconHaloBlur, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-halo-blur").value as! NSNumber).doubleValue)) } @@ -1628,7 +1628,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconHaloColor, .expression(Exp(.toColor) { Exp(.get) { @@ -1649,7 +1649,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconHaloColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-halo-color").value as! [Any], options: [])))) } @@ -1664,7 +1664,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconHaloWidth, .expression(Exp(.number) { Exp(.get) { @@ -1685,7 +1685,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconHaloWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-halo-width").value as! NSNumber).doubleValue)) } @@ -1700,7 +1700,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconImageCrossFade, .expression(Exp(.number) { Exp(.get) { @@ -1721,7 +1721,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconImageCrossFade, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-image-cross-fade").value as! NSNumber).doubleValue)) } @@ -1736,7 +1736,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOcclusionOpacity, .expression(Exp(.number) { Exp(.get) { @@ -1757,7 +1757,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOcclusionOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-occlusion-opacity").value as! NSNumber).doubleValue)) } @@ -1772,7 +1772,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOpacity, .expression(Exp(.number) { Exp(.get) { @@ -1793,7 +1793,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.iconOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-opacity").value as! NSNumber).doubleValue)) } @@ -1808,7 +1808,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textColor, .expression(Exp(.toColor) { Exp(.get) { @@ -1829,7 +1829,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-color").value as! [Any], options: [])))) } @@ -1844,7 +1844,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textEmissiveStrength, .expression(Exp(.number) { Exp(.get) { @@ -1865,7 +1865,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textEmissiveStrength, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-emissive-strength").value as! NSNumber).doubleValue)) } @@ -1880,7 +1880,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textHaloBlur, .expression(Exp(.number) { Exp(.get) { @@ -1901,7 +1901,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textHaloBlur, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-halo-blur").value as! NSNumber).doubleValue)) } @@ -1916,7 +1916,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textHaloColor, .expression(Exp(.toColor) { Exp(.get) { @@ -1937,7 +1937,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textHaloColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-halo-color").value as! [Any], options: [])))) } @@ -1952,7 +1952,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textHaloWidth, .expression(Exp(.number) { Exp(.get) { @@ -1973,7 +1973,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textHaloWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-halo-width").value as! NSNumber).doubleValue)) } @@ -1988,7 +1988,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOcclusionOpacity, .expression(Exp(.number) { Exp(.get) { @@ -2009,7 +2009,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOcclusionOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-occlusion-opacity").value as! NSNumber).doubleValue)) } @@ -2024,7 +2024,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOpacity, .expression(Exp(.number) { Exp(.get) { @@ -2045,7 +2045,7 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: SymbolLayer.self) XCTAssertEqual(layer.textOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-opacity").value as! NSNumber).doubleValue)) } @@ -2059,13 +2059,13 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { var annotation2 = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0)) annotation2.image = .init(image: try XCTUnwrap(UIImage.emptyImage()), name: "test-image-2") manager.annotations = [annotation1, annotation2] - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() XCTAssertTrue(mapView.mapboxMap.imageExists(withId: existingImage.name)) XCTAssertTrue(mapView.mapboxMap.imageExists(withId: "test-image-2")) manager.annotations = [] - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() // Images added externally will not be removed from Style when PointAnnotationManager is updated. XCTAssertTrue(mapView.mapboxMap.imageExists(withId: existingImage.name)) @@ -2086,22 +2086,22 @@ final class PointAnnotationIntegrationTests: MapViewIntegrationTestCase { pointAnnotation2.image = sharedImage otherManager.annotations = [pointAnnotation2] - manager.syncSourceAndLayerIfNeeded() - otherManager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() + otherManager.impl.syncSourceAndLayerIfNeeded() XCTAssertTrue(mapView.mapboxMap.imageExists(withId: sharedImageID)) XCTAssertTrue(manager.isUsingStyleImage(sharedImageID)) XCTAssertTrue(otherManager.isUsingStyleImage(sharedImageID)) manager.annotations = [] - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() XCTAssertTrue(mapView.mapboxMap.imageExists(withId: sharedImageID)) XCTAssertFalse(manager.isUsingStyleImage(sharedImageID)) XCTAssertTrue(otherManager.isUsingStyleImage(sharedImageID)) otherManager.annotations = [] - otherManager.syncSourceAndLayerIfNeeded() + otherManager.impl.syncSourceAndLayerIfNeeded() XCTAssertFalse(mapView.mapboxMap.imageExists(withId: sharedImageID)) XCTAssertFalse(manager.isUsingStyleImage(sharedImageID)) diff --git a/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationManagerTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationManagerTests.swift index be56e234fb44..8f4661a2bc09 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationManagerTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/PointAnnotationManagerTests.swift @@ -4,34 +4,18 @@ import XCTest final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelegate { var manager: PointAnnotationManager! - var style: MockStyle! - var id = UUID().uuidString + var harness: AnnotationManagerTestingHarness! var annotations = [PointAnnotation]() var expectation: XCTestExpectation? var delegateAnnotations: [Annotation]? - var mapFeatureQueryable: MockMapFeatureQueryable! - var imagesManager: MockAnnotationImagesManager! - var offsetCalculator: OffsetPointCalculator! - var mapboxMap: MockMapboxMap! - @TestSignal var displayLink: Signal override func setUp() { super.setUp() - style = MockStyle() - mapFeatureQueryable = MockMapFeatureQueryable() - imagesManager = MockAnnotationImagesManager() - mapboxMap = MockMapboxMap() - offsetCalculator = OffsetPointCalculator(mapboxMap: mapboxMap) + harness = AnnotationManagerTestingHarness() manager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) + params: harness.makeParams(), + deps: harness.makeDeps()) for _ in 0...10 { let annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) @@ -40,242 +24,11 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega } override func tearDown() { - style = nil - expectation = nil - delegateAnnotations = nil - imagesManager = nil - mapFeatureQueryable = nil - mapboxMap = nil - offsetCalculator = nil + harness = nil manager = nil - super.tearDown() } - func testSourceSetup() { - style.addSourceStub.reset() - - _ = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.type, SourceType.geoJson) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.id, manager.id) - } - - func testAddLayer() throws { - style.addSourceStub.reset() - let initializedManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerWithPropertiesStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.type, LayerType.symbol) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.id, initializedManager.id) - let addedLayer = try XCTUnwrap(style.addPersistentLayerStub.invocations.last?.parameters.layer as? SymbolLayer) - XCTAssertEqual(addedLayer.source, initializedManager.sourceId) - XCTAssertNil(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition) - } - - func testAddManagerWithDuplicateId() { - var annotations2 = [PointAnnotation]() - for _ in 0...50 { - let annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations2.append(annotation) - } - - manager.annotations = annotations - let manager2 = PointAnnotationManager( - id: manager.id, - style: style, - layerPosition: nil, - displayLink: displayLink, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - manager2.annotations = annotations2 - - XCTAssertEqual(manager.annotations.count, 11) - XCTAssertEqual(manager2.annotations.count, 51) - } - - func testLayerPositionPassedCorrectly() { - let manager3 = PointAnnotationManager( - id: id, - style: style, - layerPosition: LayerPosition.at(4), - displayLink: displayLink, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - manager3.annotations = annotations - - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition, LayerPosition.at(4)) - } - - func testDestroy() { - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testDestroyManagerWithDraggedAnnotations() { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.isDraggable = true - manager.annotations = [annotation] - // adds drag source/layer - _ = manager.handleDragBegin(with: annotation.id, context: .zero) - - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id, id + "_drag"]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id, id + "_drag"]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testSyncSourceAndLayer() { - manager.annotations = annotations - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - } - - func testDoNotSyncSourceAndLayerWhenNotNeeded() { - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 0) - } - - func testFeatureCollectionPassedtoGeoJSON() throws { - var annotations = [PointAnnotation]() - for _ in 0...5 { - let annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - let expectedFeatures = annotations.map(\.feature) - - manager.annotations = annotations - $displayLink.send() - - var invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, expectedFeatures) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - - do { - let annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations.append(annotation) - - manager.annotations = annotations - $displayLink.send() - - invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, [annotation].map(\.feature)) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - } - } - - @available(*, deprecated) - func testHandleTap() throws { - var annotations = [PointAnnotation]() - for _ in 0...5 { - let annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - var taps = [MapContentGestureContext]() - annotations[0].tapHandler = { context in - taps.append(context) - return true - } - annotations[1].tapHandler = { _ in - return false // skips handling - } - manager.delegate = self - - manager.annotations = annotations - - // first annotation, handles tap - let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) - var handled = manager.handleTap(layerId: "layerId", feature: annotations[0].feature, context: context) - - var result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[0].id) - XCTAssertEqual(handled, true) - - XCTAssertEqual(taps.count, 1) - XCTAssertEqual(taps.first?.point, context.point) - XCTAssertEqual(taps.first?.coordinate, context.coordinate) - - // second annotation, skips handling tap - delegateAnnotations = nil - handled = manager.handleTap(layerId: "layerId", feature: annotations[1].feature, context: context) - - result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[1].id) - XCTAssertEqual(handled, false) - - // invalid id - delegateAnnotations = nil - let invalidFeature = Feature(geometry: nil) - handled = manager.handleTap(layerId: "layerId", feature: invalidFeature, context: context) - - XCTAssertNil(delegateAnnotations) - XCTAssertEqual(handled, false) - XCTAssertEqual(taps.count, 1) - } - - func testHandleClusterTap() { - let onClusterTap = Stub(defaultReturnValue: ()) - let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) - let annotationContext = AnnotationClusterGestureContext(point: context.point, coordinate: context.coordinate, expansionZoom: 4) - manager.onClusterTap = onClusterTap.call - - let isHandled = manager.handleTap( - layerId: "mapbox-iOS-cluster-circle-layer-manager-\(id)", - feature: annotations[1].feature, - context: context - ) - mapFeatureQueryable.getGeoJsonClusterExpansionZoomStub.invocations.map(\.parameters.completion).forEach { completion in - completion(.success(FeatureExtensionValue(value: 4, features: nil))) - } - - XCTAssertTrue(isHandled) - XCTAssertEqual(mapFeatureQueryable.getGeoJsonClusterExpansionZoomStub.invocations.map(\.parameters.feature), [ - annotations[1].feature - ]) - - XCTAssertEqual(onClusterTap.invocations.map(\.parameters), [annotationContext]) - } - func testInitialIconAllowOverlap() { let initialValue = manager.iconAllowOverlap XCTAssertNil(initialValue) @@ -285,93 +38,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.iconAllowOverlap = value XCTAssertEqual(manager.iconAllowOverlap, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-allow-overlap"] as! Bool, value) - } - - func testIconAllowOverlapAnnotationPropertiesAddedWithoutDuplicate() { - let newIconAllowOverlapProperty = true - let secondIconAllowOverlapProperty = true - - manager.iconAllowOverlap = newIconAllowOverlapProperty - $displayLink.send() - manager.iconAllowOverlap = secondIconAllowOverlapProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-allow-overlap"] as! Bool, secondIconAllowOverlapProperty) - } - - func testNewIconAllowOverlapPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconAllowOverlapProperty = true - - manager.annotations = annotations - manager.iconAllowOverlap = newIconAllowOverlapProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-allow-overlap"]) + XCTAssertEqual(manager.impl.layerProperties["icon-allow-overlap"] as! Bool, value) } func testSetToNilIconAllowOverlap() { let newIconAllowOverlapProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-allow-overlap").value as! Bool manager.iconAllowOverlap = newIconAllowOverlapProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-allow-overlap"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-allow-overlap"]) + harness.triggerDisplayLink() manager.iconAllowOverlap = nil - $displayLink.send() XCTAssertNil(manager.iconAllowOverlap) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-allow-overlap"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-allow-overlap"] as! Bool, defaultValue) } - func testInitialIconIgnorePlacement() { let initialValue = manager.iconIgnorePlacement XCTAssertNil(initialValue) @@ -381,93 +63,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.iconIgnorePlacement = value XCTAssertEqual(manager.iconIgnorePlacement, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-ignore-placement"] as! Bool, value) - } - - func testIconIgnorePlacementAnnotationPropertiesAddedWithoutDuplicate() { - let newIconIgnorePlacementProperty = true - let secondIconIgnorePlacementProperty = true - - manager.iconIgnorePlacement = newIconIgnorePlacementProperty - $displayLink.send() - manager.iconIgnorePlacement = secondIconIgnorePlacementProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-ignore-placement"] as! Bool, secondIconIgnorePlacementProperty) - } - - func testNewIconIgnorePlacementPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconIgnorePlacementProperty = true - - manager.annotations = annotations - manager.iconIgnorePlacement = newIconIgnorePlacementProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-ignore-placement"]) + XCTAssertEqual(manager.impl.layerProperties["icon-ignore-placement"] as! Bool, value) } func testSetToNilIconIgnorePlacement() { let newIconIgnorePlacementProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-ignore-placement").value as! Bool manager.iconIgnorePlacement = newIconIgnorePlacementProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-ignore-placement"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-ignore-placement"]) + harness.triggerDisplayLink() manager.iconIgnorePlacement = nil - $displayLink.send() XCTAssertNil(manager.iconIgnorePlacement) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-ignore-placement"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-ignore-placement"] as! Bool, defaultValue) } - func testInitialIconKeepUpright() { let initialValue = manager.iconKeepUpright XCTAssertNil(initialValue) @@ -477,93 +88,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.iconKeepUpright = value XCTAssertEqual(manager.iconKeepUpright, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-keep-upright"] as! Bool, value) - } - - func testIconKeepUprightAnnotationPropertiesAddedWithoutDuplicate() { - let newIconKeepUprightProperty = true - let secondIconKeepUprightProperty = true - - manager.iconKeepUpright = newIconKeepUprightProperty - $displayLink.send() - manager.iconKeepUpright = secondIconKeepUprightProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-keep-upright"] as! Bool, secondIconKeepUprightProperty) - } - - func testNewIconKeepUprightPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconKeepUprightProperty = true - - manager.annotations = annotations - manager.iconKeepUpright = newIconKeepUprightProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-keep-upright"]) + XCTAssertEqual(manager.impl.layerProperties["icon-keep-upright"] as! Bool, value) } func testSetToNilIconKeepUpright() { let newIconKeepUprightProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-keep-upright").value as! Bool manager.iconKeepUpright = newIconKeepUprightProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-keep-upright"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-keep-upright"]) + harness.triggerDisplayLink() manager.iconKeepUpright = nil - $displayLink.send() XCTAssertNil(manager.iconKeepUpright) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-keep-upright"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-keep-upright"] as! Bool, defaultValue) } - func testInitialIconOptional() { let initialValue = manager.iconOptional XCTAssertNil(initialValue) @@ -573,93 +113,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.iconOptional = value XCTAssertEqual(manager.iconOptional, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-optional"] as! Bool, value) - } - - func testIconOptionalAnnotationPropertiesAddedWithoutDuplicate() { - let newIconOptionalProperty = true - let secondIconOptionalProperty = true - - manager.iconOptional = newIconOptionalProperty - $displayLink.send() - manager.iconOptional = secondIconOptionalProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-optional"] as! Bool, secondIconOptionalProperty) - } - - func testNewIconOptionalPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconOptionalProperty = true - - manager.annotations = annotations - manager.iconOptional = newIconOptionalProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-optional"]) + XCTAssertEqual(manager.impl.layerProperties["icon-optional"] as! Bool, value) } func testSetToNilIconOptional() { let newIconOptionalProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-optional").value as! Bool manager.iconOptional = newIconOptionalProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-optional"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-optional"]) + harness.triggerDisplayLink() manager.iconOptional = nil - $displayLink.send() XCTAssertNil(manager.iconOptional) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-optional"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-optional"] as! Bool, defaultValue) } - func testInitialIconPadding() { let initialValue = manager.iconPadding XCTAssertNil(initialValue) @@ -669,93 +138,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = 50000.0 manager.iconPadding = value XCTAssertEqual(manager.iconPadding, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-padding"] as! Double, value) - } - - func testIconPaddingAnnotationPropertiesAddedWithoutDuplicate() { - let newIconPaddingProperty = 50000.0 - let secondIconPaddingProperty = 50000.0 - - manager.iconPadding = newIconPaddingProperty - $displayLink.send() - manager.iconPadding = secondIconPaddingProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-padding"] as! Double, secondIconPaddingProperty) - } - - func testNewIconPaddingPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconPaddingProperty = 50000.0 - - manager.annotations = annotations - manager.iconPadding = newIconPaddingProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-padding"]) + XCTAssertEqual(manager.impl.layerProperties["icon-padding"] as! Double, value) } func testSetToNilIconPadding() { let newIconPaddingProperty = 50000.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-padding").value as! Double manager.iconPadding = newIconPaddingProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-padding"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-padding"]) + harness.triggerDisplayLink() manager.iconPadding = nil - $displayLink.send() XCTAssertNil(manager.iconPadding) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-padding"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-padding"] as! Double, defaultValue) } - func testInitialIconPitchAlignment() { let initialValue = manager.iconPitchAlignment XCTAssertNil(initialValue) @@ -765,93 +163,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = IconPitchAlignment.testConstantValue() manager.iconPitchAlignment = value XCTAssertEqual(manager.iconPitchAlignment, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-pitch-alignment"] as! String, value.rawValue) - } - - func testIconPitchAlignmentAnnotationPropertiesAddedWithoutDuplicate() { - let newIconPitchAlignmentProperty = IconPitchAlignment.testConstantValue() - let secondIconPitchAlignmentProperty = IconPitchAlignment.testConstantValue() - - manager.iconPitchAlignment = newIconPitchAlignmentProperty - $displayLink.send() - manager.iconPitchAlignment = secondIconPitchAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-pitch-alignment"] as! String, secondIconPitchAlignmentProperty.rawValue) - } - - func testNewIconPitchAlignmentPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconPitchAlignmentProperty = IconPitchAlignment.testConstantValue() - - manager.annotations = annotations - manager.iconPitchAlignment = newIconPitchAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-pitch-alignment"]) + XCTAssertEqual(manager.impl.layerProperties["icon-pitch-alignment"] as! String, value.rawValue) } func testSetToNilIconPitchAlignment() { let newIconPitchAlignmentProperty = IconPitchAlignment.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-pitch-alignment").value as! String manager.iconPitchAlignment = newIconPitchAlignmentProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-pitch-alignment"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-pitch-alignment"]) + harness.triggerDisplayLink() manager.iconPitchAlignment = nil - $displayLink.send() XCTAssertNil(manager.iconPitchAlignment) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-pitch-alignment"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-pitch-alignment"] as! String, defaultValue) } - func testInitialIconRotationAlignment() { let initialValue = manager.iconRotationAlignment XCTAssertNil(initialValue) @@ -861,93 +188,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = IconRotationAlignment.testConstantValue() manager.iconRotationAlignment = value XCTAssertEqual(manager.iconRotationAlignment, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-rotation-alignment"] as! String, value.rawValue) - } - - func testIconRotationAlignmentAnnotationPropertiesAddedWithoutDuplicate() { - let newIconRotationAlignmentProperty = IconRotationAlignment.testConstantValue() - let secondIconRotationAlignmentProperty = IconRotationAlignment.testConstantValue() - - manager.iconRotationAlignment = newIconRotationAlignmentProperty - $displayLink.send() - manager.iconRotationAlignment = secondIconRotationAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-rotation-alignment"] as! String, secondIconRotationAlignmentProperty.rawValue) - } - - func testNewIconRotationAlignmentPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconRotationAlignmentProperty = IconRotationAlignment.testConstantValue() - - manager.annotations = annotations - manager.iconRotationAlignment = newIconRotationAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-rotation-alignment"]) + XCTAssertEqual(manager.impl.layerProperties["icon-rotation-alignment"] as! String, value.rawValue) } func testSetToNilIconRotationAlignment() { let newIconRotationAlignmentProperty = IconRotationAlignment.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-rotation-alignment").value as! String manager.iconRotationAlignment = newIconRotationAlignmentProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-rotation-alignment"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-rotation-alignment"]) + harness.triggerDisplayLink() manager.iconRotationAlignment = nil - $displayLink.send() XCTAssertNil(manager.iconRotationAlignment) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-rotation-alignment"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-rotation-alignment"] as! String, defaultValue) } - func testInitialSymbolAvoidEdges() { let initialValue = manager.symbolAvoidEdges XCTAssertNil(initialValue) @@ -957,93 +213,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.symbolAvoidEdges = value XCTAssertEqual(manager.symbolAvoidEdges, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-avoid-edges"] as! Bool, value) - } - - func testSymbolAvoidEdgesAnnotationPropertiesAddedWithoutDuplicate() { - let newSymbolAvoidEdgesProperty = true - let secondSymbolAvoidEdgesProperty = true - - manager.symbolAvoidEdges = newSymbolAvoidEdgesProperty - $displayLink.send() - manager.symbolAvoidEdges = secondSymbolAvoidEdgesProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-avoid-edges"] as! Bool, secondSymbolAvoidEdgesProperty) - } - - func testNewSymbolAvoidEdgesPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newSymbolAvoidEdgesProperty = true - - manager.annotations = annotations - manager.symbolAvoidEdges = newSymbolAvoidEdgesProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-avoid-edges"]) + XCTAssertEqual(manager.impl.layerProperties["symbol-avoid-edges"] as! Bool, value) } func testSetToNilSymbolAvoidEdges() { let newSymbolAvoidEdgesProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-avoid-edges").value as! Bool manager.symbolAvoidEdges = newSymbolAvoidEdgesProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-avoid-edges"]) + XCTAssertNotNil(manager.impl.layerProperties["symbol-avoid-edges"]) + harness.triggerDisplayLink() manager.symbolAvoidEdges = nil - $displayLink.send() XCTAssertNil(manager.symbolAvoidEdges) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-avoid-edges"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-avoid-edges"] as! Bool, defaultValue) } - func testInitialSymbolPlacement() { let initialValue = manager.symbolPlacement XCTAssertNil(initialValue) @@ -1053,93 +238,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = SymbolPlacement.testConstantValue() manager.symbolPlacement = value XCTAssertEqual(manager.symbolPlacement, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-placement"] as! String, value.rawValue) - } - - func testSymbolPlacementAnnotationPropertiesAddedWithoutDuplicate() { - let newSymbolPlacementProperty = SymbolPlacement.testConstantValue() - let secondSymbolPlacementProperty = SymbolPlacement.testConstantValue() - - manager.symbolPlacement = newSymbolPlacementProperty - $displayLink.send() - manager.symbolPlacement = secondSymbolPlacementProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-placement"] as! String, secondSymbolPlacementProperty.rawValue) - } - - func testNewSymbolPlacementPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newSymbolPlacementProperty = SymbolPlacement.testConstantValue() - - manager.annotations = annotations - manager.symbolPlacement = newSymbolPlacementProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-placement"]) + XCTAssertEqual(manager.impl.layerProperties["symbol-placement"] as! String, value.rawValue) } func testSetToNilSymbolPlacement() { let newSymbolPlacementProperty = SymbolPlacement.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-placement").value as! String manager.symbolPlacement = newSymbolPlacementProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-placement"]) + XCTAssertNotNil(manager.impl.layerProperties["symbol-placement"]) + harness.triggerDisplayLink() manager.symbolPlacement = nil - $displayLink.send() XCTAssertNil(manager.symbolPlacement) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-placement"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-placement"] as! String, defaultValue) } - func testInitialSymbolSpacing() { let initialValue = manager.symbolSpacing XCTAssertNil(initialValue) @@ -1149,93 +263,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = 50000.5 manager.symbolSpacing = value XCTAssertEqual(manager.symbolSpacing, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-spacing"] as! Double, value) - } - - func testSymbolSpacingAnnotationPropertiesAddedWithoutDuplicate() { - let newSymbolSpacingProperty = 50000.5 - let secondSymbolSpacingProperty = 50000.5 - - manager.symbolSpacing = newSymbolSpacingProperty - $displayLink.send() - manager.symbolSpacing = secondSymbolSpacingProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-spacing"] as! Double, secondSymbolSpacingProperty) - } - - func testNewSymbolSpacingPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newSymbolSpacingProperty = 50000.5 - - manager.annotations = annotations - manager.symbolSpacing = newSymbolSpacingProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-spacing"]) + XCTAssertEqual(manager.impl.layerProperties["symbol-spacing"] as! Double, value) } func testSetToNilSymbolSpacing() { let newSymbolSpacingProperty = 50000.5 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-spacing").value as! Double manager.symbolSpacing = newSymbolSpacingProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-spacing"]) + XCTAssertNotNil(manager.impl.layerProperties["symbol-spacing"]) + harness.triggerDisplayLink() manager.symbolSpacing = nil - $displayLink.send() XCTAssertNil(manager.symbolSpacing) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-spacing"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-spacing"] as! Double, defaultValue) } - func testInitialSymbolZElevate() { let initialValue = manager.symbolZElevate XCTAssertNil(initialValue) @@ -1245,93 +288,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.symbolZElevate = value XCTAssertEqual(manager.symbolZElevate, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-elevate"] as! Bool, value) - } - - func testSymbolZElevateAnnotationPropertiesAddedWithoutDuplicate() { - let newSymbolZElevateProperty = true - let secondSymbolZElevateProperty = true - - manager.symbolZElevate = newSymbolZElevateProperty - $displayLink.send() - manager.symbolZElevate = secondSymbolZElevateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-elevate"] as! Bool, secondSymbolZElevateProperty) - } - - func testNewSymbolZElevatePropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newSymbolZElevateProperty = true - - manager.annotations = annotations - manager.symbolZElevate = newSymbolZElevateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-elevate"]) + XCTAssertEqual(manager.impl.layerProperties["symbol-z-elevate"] as! Bool, value) } func testSetToNilSymbolZElevate() { let newSymbolZElevateProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-z-elevate").value as! Bool manager.symbolZElevate = newSymbolZElevateProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-elevate"]) + XCTAssertNotNil(manager.impl.layerProperties["symbol-z-elevate"]) + harness.triggerDisplayLink() manager.symbolZElevate = nil - $displayLink.send() XCTAssertNil(manager.symbolZElevate) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-elevate"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-elevate"] as! Bool, defaultValue) } - func testInitialSymbolZOrder() { let initialValue = manager.symbolZOrder XCTAssertNil(initialValue) @@ -1341,93 +313,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = SymbolZOrder.testConstantValue() manager.symbolZOrder = value XCTAssertEqual(manager.symbolZOrder, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-order"] as! String, value.rawValue) - } - - func testSymbolZOrderAnnotationPropertiesAddedWithoutDuplicate() { - let newSymbolZOrderProperty = SymbolZOrder.testConstantValue() - let secondSymbolZOrderProperty = SymbolZOrder.testConstantValue() - - manager.symbolZOrder = newSymbolZOrderProperty - $displayLink.send() - manager.symbolZOrder = secondSymbolZOrderProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-order"] as! String, secondSymbolZOrderProperty.rawValue) - } - - func testNewSymbolZOrderPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newSymbolZOrderProperty = SymbolZOrder.testConstantValue() - - manager.annotations = annotations - manager.symbolZOrder = newSymbolZOrderProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-order"]) + XCTAssertEqual(manager.impl.layerProperties["symbol-z-order"] as! String, value.rawValue) } func testSetToNilSymbolZOrder() { let newSymbolZOrderProperty = SymbolZOrder.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "symbol-z-order").value as! String manager.symbolZOrder = newSymbolZOrderProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-order"]) + XCTAssertNotNil(manager.impl.layerProperties["symbol-z-order"]) + harness.triggerDisplayLink() manager.symbolZOrder = nil - $displayLink.send() XCTAssertNil(manager.symbolZOrder) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-order"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["symbol-z-order"] as! String, defaultValue) } - func testInitialTextAllowOverlap() { let initialValue = manager.textAllowOverlap XCTAssertNil(initialValue) @@ -1437,93 +338,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.textAllowOverlap = value XCTAssertEqual(manager.textAllowOverlap, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-allow-overlap"] as! Bool, value) - } - - func testTextAllowOverlapAnnotationPropertiesAddedWithoutDuplicate() { - let newTextAllowOverlapProperty = true - let secondTextAllowOverlapProperty = true - - manager.textAllowOverlap = newTextAllowOverlapProperty - $displayLink.send() - manager.textAllowOverlap = secondTextAllowOverlapProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-allow-overlap"] as! Bool, secondTextAllowOverlapProperty) - } - - func testNewTextAllowOverlapPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextAllowOverlapProperty = true - - manager.annotations = annotations - manager.textAllowOverlap = newTextAllowOverlapProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-allow-overlap"]) + XCTAssertEqual(manager.impl.layerProperties["text-allow-overlap"] as! Bool, value) } func testSetToNilTextAllowOverlap() { let newTextAllowOverlapProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-allow-overlap").value as! Bool manager.textAllowOverlap = newTextAllowOverlapProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-allow-overlap"]) + XCTAssertNotNil(manager.impl.layerProperties["text-allow-overlap"]) + harness.triggerDisplayLink() manager.textAllowOverlap = nil - $displayLink.send() XCTAssertNil(manager.textAllowOverlap) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-allow-overlap"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-allow-overlap"] as! Bool, defaultValue) } - func testInitialTextFont() { let initialValue = manager.textFont XCTAssertNil(initialValue) @@ -1533,93 +363,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = Array.random(withLength: .random(in: 0...10), generator: { UUID().uuidString }) manager.textFont = value XCTAssertEqual(manager.textFont, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual((style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-font"] as! [Any])[1] as! [String], value) - } - - func testTextFontAnnotationPropertiesAddedWithoutDuplicate() { - let newTextFontProperty = Array.random(withLength: .random(in: 0...10), generator: { UUID().uuidString }) - let secondTextFontProperty = Array.random(withLength: .random(in: 0...10), generator: { UUID().uuidString }) - - manager.textFont = newTextFontProperty - $displayLink.send() - manager.textFont = secondTextFontProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual((style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-font"] as! [Any])[1] as! [String], secondTextFontProperty) - } - - func testNewTextFontPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextFontProperty = Array.random(withLength: .random(in: 0...10), generator: { UUID().uuidString }) - - manager.annotations = annotations - manager.textFont = newTextFontProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-font"]) + XCTAssertEqual((manager.impl.layerProperties["text-font"] as! [Any])[1] as! [String], value) } func testSetToNilTextFont() { let newTextFontProperty = Array.random(withLength: .random(in: 0...10), generator: { UUID().uuidString }) let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-font").value as! [String] manager.textFont = newTextFontProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-font"]) + XCTAssertNotNil(manager.impl.layerProperties["text-font"]) + harness.triggerDisplayLink() manager.textFont = nil - $displayLink.send() XCTAssertNil(manager.textFont) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-font"] as! [String], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-font"] as! [String], defaultValue) } - func testInitialTextIgnorePlacement() { let initialValue = manager.textIgnorePlacement XCTAssertNil(initialValue) @@ -1629,93 +388,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.textIgnorePlacement = value XCTAssertEqual(manager.textIgnorePlacement, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-ignore-placement"] as! Bool, value) - } - - func testTextIgnorePlacementAnnotationPropertiesAddedWithoutDuplicate() { - let newTextIgnorePlacementProperty = true - let secondTextIgnorePlacementProperty = true - - manager.textIgnorePlacement = newTextIgnorePlacementProperty - $displayLink.send() - manager.textIgnorePlacement = secondTextIgnorePlacementProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-ignore-placement"] as! Bool, secondTextIgnorePlacementProperty) - } - - func testNewTextIgnorePlacementPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextIgnorePlacementProperty = true - - manager.annotations = annotations - manager.textIgnorePlacement = newTextIgnorePlacementProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-ignore-placement"]) + XCTAssertEqual(manager.impl.layerProperties["text-ignore-placement"] as! Bool, value) } func testSetToNilTextIgnorePlacement() { let newTextIgnorePlacementProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-ignore-placement").value as! Bool manager.textIgnorePlacement = newTextIgnorePlacementProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-ignore-placement"]) + XCTAssertNotNil(manager.impl.layerProperties["text-ignore-placement"]) + harness.triggerDisplayLink() manager.textIgnorePlacement = nil - $displayLink.send() XCTAssertNil(manager.textIgnorePlacement) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-ignore-placement"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-ignore-placement"] as! Bool, defaultValue) } - func testInitialTextKeepUpright() { let initialValue = manager.textKeepUpright XCTAssertNil(initialValue) @@ -1725,93 +413,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.textKeepUpright = value XCTAssertEqual(manager.textKeepUpright, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-keep-upright"] as! Bool, value) - } - - func testTextKeepUprightAnnotationPropertiesAddedWithoutDuplicate() { - let newTextKeepUprightProperty = true - let secondTextKeepUprightProperty = true - - manager.textKeepUpright = newTextKeepUprightProperty - $displayLink.send() - manager.textKeepUpright = secondTextKeepUprightProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-keep-upright"] as! Bool, secondTextKeepUprightProperty) - } - - func testNewTextKeepUprightPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextKeepUprightProperty = true - - manager.annotations = annotations - manager.textKeepUpright = newTextKeepUprightProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-keep-upright"]) + XCTAssertEqual(manager.impl.layerProperties["text-keep-upright"] as! Bool, value) } func testSetToNilTextKeepUpright() { let newTextKeepUprightProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-keep-upright").value as! Bool manager.textKeepUpright = newTextKeepUprightProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-keep-upright"]) + XCTAssertNotNil(manager.impl.layerProperties["text-keep-upright"]) + harness.triggerDisplayLink() manager.textKeepUpright = nil - $displayLink.send() XCTAssertNil(manager.textKeepUpright) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-keep-upright"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-keep-upright"] as! Bool, defaultValue) } - func testInitialTextMaxAngle() { let initialValue = manager.textMaxAngle XCTAssertNil(initialValue) @@ -1821,93 +438,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = 0.0 manager.textMaxAngle = value XCTAssertEqual(manager.textMaxAngle, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-max-angle"] as! Double, value) - } - - func testTextMaxAngleAnnotationPropertiesAddedWithoutDuplicate() { - let newTextMaxAngleProperty = 0.0 - let secondTextMaxAngleProperty = 0.0 - - manager.textMaxAngle = newTextMaxAngleProperty - $displayLink.send() - manager.textMaxAngle = secondTextMaxAngleProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-max-angle"] as! Double, secondTextMaxAngleProperty) - } - - func testNewTextMaxAnglePropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextMaxAngleProperty = 0.0 - - manager.annotations = annotations - manager.textMaxAngle = newTextMaxAngleProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-max-angle"]) + XCTAssertEqual(manager.impl.layerProperties["text-max-angle"] as! Double, value) } func testSetToNilTextMaxAngle() { let newTextMaxAngleProperty = 0.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-max-angle").value as! Double manager.textMaxAngle = newTextMaxAngleProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-max-angle"]) + XCTAssertNotNil(manager.impl.layerProperties["text-max-angle"]) + harness.triggerDisplayLink() manager.textMaxAngle = nil - $displayLink.send() XCTAssertNil(manager.textMaxAngle) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-max-angle"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-max-angle"] as! Double, defaultValue) } - func testInitialTextOptional() { let initialValue = manager.textOptional XCTAssertNil(initialValue) @@ -1917,93 +463,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = true manager.textOptional = value XCTAssertEqual(manager.textOptional, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-optional"] as! Bool, value) - } - - func testTextOptionalAnnotationPropertiesAddedWithoutDuplicate() { - let newTextOptionalProperty = true - let secondTextOptionalProperty = true - - manager.textOptional = newTextOptionalProperty - $displayLink.send() - manager.textOptional = secondTextOptionalProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-optional"] as! Bool, secondTextOptionalProperty) - } - - func testNewTextOptionalPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextOptionalProperty = true - - manager.annotations = annotations - manager.textOptional = newTextOptionalProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-optional"]) + XCTAssertEqual(manager.impl.layerProperties["text-optional"] as! Bool, value) } func testSetToNilTextOptional() { let newTextOptionalProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-optional").value as! Bool manager.textOptional = newTextOptionalProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-optional"]) + XCTAssertNotNil(manager.impl.layerProperties["text-optional"]) + harness.triggerDisplayLink() manager.textOptional = nil - $displayLink.send() XCTAssertNil(manager.textOptional) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-optional"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-optional"] as! Bool, defaultValue) } - func testInitialTextPadding() { let initialValue = manager.textPadding XCTAssertNil(initialValue) @@ -2013,189 +488,47 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = 50000.0 manager.textPadding = value XCTAssertEqual(manager.textPadding, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-padding"] as! Double, value) - } - - func testTextPaddingAnnotationPropertiesAddedWithoutDuplicate() { - let newTextPaddingProperty = 50000.0 - let secondTextPaddingProperty = 50000.0 - - manager.textPadding = newTextPaddingProperty - $displayLink.send() - manager.textPadding = secondTextPaddingProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-padding"] as! Double, secondTextPaddingProperty) - } - - func testNewTextPaddingPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextPaddingProperty = 50000.0 - - manager.annotations = annotations - manager.textPadding = newTextPaddingProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-padding"]) + XCTAssertEqual(manager.impl.layerProperties["text-padding"] as! Double, value) } func testSetToNilTextPadding() { let newTextPaddingProperty = 50000.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-padding").value as! Double manager.textPadding = newTextPaddingProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-padding"]) + XCTAssertNotNil(manager.impl.layerProperties["text-padding"]) + harness.triggerDisplayLink() manager.textPadding = nil - $displayLink.send() XCTAssertNil(manager.textPadding) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-padding"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-padding"] as! Double, defaultValue) + } + func testInitialTextPitchAlignment() { + let initialValue = manager.textPitchAlignment + XCTAssertNil(initialValue) } - func testInitialTextPitchAlignment() { - let initialValue = manager.textPitchAlignment - XCTAssertNil(initialValue) - } - - func testSetTextPitchAlignment() { - let value = TextPitchAlignment.testConstantValue() - manager.textPitchAlignment = value - XCTAssertEqual(manager.textPitchAlignment, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-pitch-alignment"] as! String, value.rawValue) - } - - func testTextPitchAlignmentAnnotationPropertiesAddedWithoutDuplicate() { - let newTextPitchAlignmentProperty = TextPitchAlignment.testConstantValue() - let secondTextPitchAlignmentProperty = TextPitchAlignment.testConstantValue() - - manager.textPitchAlignment = newTextPitchAlignmentProperty - $displayLink.send() - manager.textPitchAlignment = secondTextPitchAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-pitch-alignment"] as! String, secondTextPitchAlignmentProperty.rawValue) - } - - func testNewTextPitchAlignmentPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextPitchAlignmentProperty = TextPitchAlignment.testConstantValue() - - manager.annotations = annotations - manager.textPitchAlignment = newTextPitchAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-pitch-alignment"]) + func testSetTextPitchAlignment() { + let value = TextPitchAlignment.testConstantValue() + manager.textPitchAlignment = value + XCTAssertEqual(manager.textPitchAlignment, value) + XCTAssertEqual(manager.impl.layerProperties["text-pitch-alignment"] as! String, value.rawValue) } func testSetToNilTextPitchAlignment() { let newTextPitchAlignmentProperty = TextPitchAlignment.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-pitch-alignment").value as! String manager.textPitchAlignment = newTextPitchAlignmentProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-pitch-alignment"]) + XCTAssertNotNil(manager.impl.layerProperties["text-pitch-alignment"]) + harness.triggerDisplayLink() manager.textPitchAlignment = nil - $displayLink.send() XCTAssertNil(manager.textPitchAlignment) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-pitch-alignment"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-pitch-alignment"] as! String, defaultValue) } - func testInitialTextRotationAlignment() { let initialValue = manager.textRotationAlignment XCTAssertNil(initialValue) @@ -2205,93 +538,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = TextRotationAlignment.testConstantValue() manager.textRotationAlignment = value XCTAssertEqual(manager.textRotationAlignment, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-rotation-alignment"] as! String, value.rawValue) - } - - func testTextRotationAlignmentAnnotationPropertiesAddedWithoutDuplicate() { - let newTextRotationAlignmentProperty = TextRotationAlignment.testConstantValue() - let secondTextRotationAlignmentProperty = TextRotationAlignment.testConstantValue() - - manager.textRotationAlignment = newTextRotationAlignmentProperty - $displayLink.send() - manager.textRotationAlignment = secondTextRotationAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-rotation-alignment"] as! String, secondTextRotationAlignmentProperty.rawValue) - } - - func testNewTextRotationAlignmentPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextRotationAlignmentProperty = TextRotationAlignment.testConstantValue() - - manager.annotations = annotations - manager.textRotationAlignment = newTextRotationAlignmentProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-rotation-alignment"]) + XCTAssertEqual(manager.impl.layerProperties["text-rotation-alignment"] as! String, value.rawValue) } func testSetToNilTextRotationAlignment() { let newTextRotationAlignmentProperty = TextRotationAlignment.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-rotation-alignment").value as! String manager.textRotationAlignment = newTextRotationAlignmentProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-rotation-alignment"]) + XCTAssertNotNil(manager.impl.layerProperties["text-rotation-alignment"]) + harness.triggerDisplayLink() manager.textRotationAlignment = nil - $displayLink.send() XCTAssertNil(manager.textRotationAlignment) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-rotation-alignment"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-rotation-alignment"] as! String, defaultValue) } - func testInitialTextVariableAnchor() { let initialValue = manager.textVariableAnchor XCTAssertNil(initialValue) @@ -2301,95 +563,23 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = Array.random(withLength: .random(in: 0...10), generator: { TextAnchor.testConstantValue() }) manager.textVariableAnchor = value XCTAssertEqual(manager.textVariableAnchor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) let valueAsString = value.map { $0.rawValue } - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-variable-anchor"] as! [String], valueAsString) - } - - func testTextVariableAnchorAnnotationPropertiesAddedWithoutDuplicate() { - let newTextVariableAnchorProperty = Array.random(withLength: .random(in: 0...10), generator: { TextAnchor.testConstantValue() }) - let secondTextVariableAnchorProperty = Array.random(withLength: .random(in: 0...10), generator: { TextAnchor.testConstantValue() }) - - manager.textVariableAnchor = newTextVariableAnchorProperty - $displayLink.send() - manager.textVariableAnchor = secondTextVariableAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - let valueAsString = secondTextVariableAnchorProperty.map { $0.rawValue } - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-variable-anchor"] as! [String], valueAsString) - } - - func testNewTextVariableAnchorPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextVariableAnchorProperty = Array.random(withLength: .random(in: 0...10), generator: { TextAnchor.testConstantValue() }) - - manager.annotations = annotations - manager.textVariableAnchor = newTextVariableAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-variable-anchor"]) + XCTAssertEqual(manager.impl.layerProperties["text-variable-anchor"] as! [String], valueAsString) } func testSetToNilTextVariableAnchor() { let newTextVariableAnchorProperty = Array.random(withLength: .random(in: 0...10), generator: { TextAnchor.testConstantValue() }) let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-variable-anchor").value as! [TextAnchor] manager.textVariableAnchor = newTextVariableAnchorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-variable-anchor"]) + XCTAssertNotNil(manager.impl.layerProperties["text-variable-anchor"]) + harness.triggerDisplayLink() manager.textVariableAnchor = nil - $displayLink.send() XCTAssertNil(manager.textVariableAnchor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-variable-anchor"] as! [TextAnchor], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-variable-anchor"] as! [TextAnchor], defaultValue) } - func testInitialTextWritingMode() { let initialValue = manager.textWritingMode XCTAssertNil(initialValue) @@ -2399,95 +589,23 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = Array.random(withLength: .random(in: 0...10), generator: { TextWritingMode.testConstantValue() }) manager.textWritingMode = value XCTAssertEqual(manager.textWritingMode, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) let valueAsString = value.map { $0.rawValue } - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-writing-mode"] as! [String], valueAsString) - } - - func testTextWritingModeAnnotationPropertiesAddedWithoutDuplicate() { - let newTextWritingModeProperty = Array.random(withLength: .random(in: 0...10), generator: { TextWritingMode.testConstantValue() }) - let secondTextWritingModeProperty = Array.random(withLength: .random(in: 0...10), generator: { TextWritingMode.testConstantValue() }) - - manager.textWritingMode = newTextWritingModeProperty - $displayLink.send() - manager.textWritingMode = secondTextWritingModeProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - let valueAsString = secondTextWritingModeProperty.map { $0.rawValue } - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-writing-mode"] as! [String], valueAsString) - } - - func testNewTextWritingModePropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextWritingModeProperty = Array.random(withLength: .random(in: 0...10), generator: { TextWritingMode.testConstantValue() }) - - manager.annotations = annotations - manager.textWritingMode = newTextWritingModeProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-writing-mode"]) + XCTAssertEqual(manager.impl.layerProperties["text-writing-mode"] as! [String], valueAsString) } func testSetToNilTextWritingMode() { let newTextWritingModeProperty = Array.random(withLength: .random(in: 0...10), generator: { TextWritingMode.testConstantValue() }) let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-writing-mode").value as! [TextWritingMode] manager.textWritingMode = newTextWritingModeProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-writing-mode"]) + XCTAssertNotNil(manager.impl.layerProperties["text-writing-mode"]) + harness.triggerDisplayLink() manager.textWritingMode = nil - $displayLink.send() XCTAssertNil(manager.textWritingMode) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-writing-mode"] as! [TextWritingMode], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-writing-mode"] as! [TextWritingMode], defaultValue) } - func testInitialIconColorSaturation() { let initialValue = manager.iconColorSaturation XCTAssertNil(initialValue) @@ -2497,93 +615,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = 0.0 manager.iconColorSaturation = value XCTAssertEqual(manager.iconColorSaturation, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-color-saturation"] as! Double, value) - } - - func testIconColorSaturationAnnotationPropertiesAddedWithoutDuplicate() { - let newIconColorSaturationProperty = 0.0 - let secondIconColorSaturationProperty = 0.0 - - manager.iconColorSaturation = newIconColorSaturationProperty - $displayLink.send() - manager.iconColorSaturation = secondIconColorSaturationProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-color-saturation"] as! Double, secondIconColorSaturationProperty) - } - - func testNewIconColorSaturationPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconColorSaturationProperty = 0.0 - - manager.annotations = annotations - manager.iconColorSaturation = newIconColorSaturationProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-color-saturation"]) + XCTAssertEqual(manager.impl.layerProperties["icon-color-saturation"] as! Double, value) } func testSetToNilIconColorSaturation() { let newIconColorSaturationProperty = 0.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-color-saturation").value as! Double manager.iconColorSaturation = newIconColorSaturationProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-color-saturation"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-color-saturation"]) + harness.triggerDisplayLink() manager.iconColorSaturation = nil - $displayLink.send() XCTAssertNil(manager.iconColorSaturation) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-color-saturation"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-color-saturation"] as! Double, defaultValue) } - func testInitialIconTranslate() { let initialValue = manager.iconTranslate XCTAssertNil(initialValue) @@ -2593,93 +640,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = [0.0, 0.0] manager.iconTranslate = value XCTAssertEqual(manager.iconTranslate, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate"] as! [Double], value) - } - - func testIconTranslateAnnotationPropertiesAddedWithoutDuplicate() { - let newIconTranslateProperty = [0.0, 0.0] - let secondIconTranslateProperty = [0.0, 0.0] - - manager.iconTranslate = newIconTranslateProperty - $displayLink.send() - manager.iconTranslate = secondIconTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate"] as! [Double], secondIconTranslateProperty) - } - - func testNewIconTranslatePropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconTranslateProperty = [0.0, 0.0] - - manager.annotations = annotations - manager.iconTranslate = newIconTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate"]) + XCTAssertEqual(manager.impl.layerProperties["icon-translate"] as! [Double], value) } func testSetToNilIconTranslate() { let newIconTranslateProperty = [0.0, 0.0] let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-translate").value as! [Double] manager.iconTranslate = newIconTranslateProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-translate"]) + harness.triggerDisplayLink() manager.iconTranslate = nil - $displayLink.send() XCTAssertNil(manager.iconTranslate) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate"] as! [Double], defaultValue) } - func testInitialIconTranslateAnchor() { let initialValue = manager.iconTranslateAnchor XCTAssertNil(initialValue) @@ -2689,93 +665,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = IconTranslateAnchor.testConstantValue() manager.iconTranslateAnchor = value XCTAssertEqual(manager.iconTranslateAnchor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate-anchor"] as! String, value.rawValue) - } - - func testIconTranslateAnchorAnnotationPropertiesAddedWithoutDuplicate() { - let newIconTranslateAnchorProperty = IconTranslateAnchor.testConstantValue() - let secondIconTranslateAnchorProperty = IconTranslateAnchor.testConstantValue() - - manager.iconTranslateAnchor = newIconTranslateAnchorProperty - $displayLink.send() - manager.iconTranslateAnchor = secondIconTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate-anchor"] as! String, secondIconTranslateAnchorProperty.rawValue) - } - - func testNewIconTranslateAnchorPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newIconTranslateAnchorProperty = IconTranslateAnchor.testConstantValue() - - manager.annotations = annotations - manager.iconTranslateAnchor = newIconTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate-anchor"]) + XCTAssertEqual(manager.impl.layerProperties["icon-translate-anchor"] as! String, value.rawValue) } func testSetToNilIconTranslateAnchor() { let newIconTranslateAnchorProperty = IconTranslateAnchor.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "icon-translate-anchor").value as! String manager.iconTranslateAnchor = newIconTranslateAnchorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate-anchor"]) + XCTAssertNotNil(manager.impl.layerProperties["icon-translate-anchor"]) + harness.triggerDisplayLink() manager.iconTranslateAnchor = nil - $displayLink.send() XCTAssertNil(manager.iconTranslateAnchor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate-anchor"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["icon-translate-anchor"] as! String, defaultValue) } - func testInitialTextTranslate() { let initialValue = manager.textTranslate XCTAssertNil(initialValue) @@ -2785,93 +690,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = [0.0, 0.0] manager.textTranslate = value XCTAssertEqual(manager.textTranslate, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate"] as! [Double], value) - } - - func testTextTranslateAnnotationPropertiesAddedWithoutDuplicate() { - let newTextTranslateProperty = [0.0, 0.0] - let secondTextTranslateProperty = [0.0, 0.0] - - manager.textTranslate = newTextTranslateProperty - $displayLink.send() - manager.textTranslate = secondTextTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate"] as! [Double], secondTextTranslateProperty) - } - - func testNewTextTranslatePropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextTranslateProperty = [0.0, 0.0] - - manager.annotations = annotations - manager.textTranslate = newTextTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate"]) + XCTAssertEqual(manager.impl.layerProperties["text-translate"] as! [Double], value) } func testSetToNilTextTranslate() { let newTextTranslateProperty = [0.0, 0.0] let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-translate").value as! [Double] manager.textTranslate = newTextTranslateProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate"]) + XCTAssertNotNil(manager.impl.layerProperties["text-translate"]) + harness.triggerDisplayLink() manager.textTranslate = nil - $displayLink.send() XCTAssertNil(manager.textTranslate) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate"] as! [Double], defaultValue) } - func testInitialTextTranslateAnchor() { let initialValue = manager.textTranslateAnchor XCTAssertNil(initialValue) @@ -2881,93 +715,22 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = TextTranslateAnchor.testConstantValue() manager.textTranslateAnchor = value XCTAssertEqual(manager.textTranslateAnchor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate-anchor"] as! String, value.rawValue) - } - - func testTextTranslateAnchorAnnotationPropertiesAddedWithoutDuplicate() { - let newTextTranslateAnchorProperty = TextTranslateAnchor.testConstantValue() - let secondTextTranslateAnchorProperty = TextTranslateAnchor.testConstantValue() - - manager.textTranslateAnchor = newTextTranslateAnchorProperty - $displayLink.send() - manager.textTranslateAnchor = secondTextTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate-anchor"] as! String, secondTextTranslateAnchorProperty.rawValue) - } - - func testNewTextTranslateAnchorPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newTextTranslateAnchorProperty = TextTranslateAnchor.testConstantValue() - - manager.annotations = annotations - manager.textTranslateAnchor = newTextTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate-anchor"]) + XCTAssertEqual(manager.impl.layerProperties["text-translate-anchor"] as! String, value.rawValue) } func testSetToNilTextTranslateAnchor() { let newTextTranslateAnchorProperty = TextTranslateAnchor.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "text-translate-anchor").value as! String manager.textTranslateAnchor = newTextTranslateAnchorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate-anchor"]) + XCTAssertNotNil(manager.impl.layerProperties["text-translate-anchor"]) + harness.triggerDisplayLink() manager.textTranslateAnchor = nil - $displayLink.send() XCTAssertNil(manager.textTranslateAnchor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate-anchor"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["text-translate-anchor"] as! String, defaultValue) } - func testInitialSlot() { let initialValue = manager.slot XCTAssertNil(initialValue) @@ -2977,91 +740,21 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega let value = UUID().uuidString manager.slot = value XCTAssertEqual(manager.slot, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, value) - } - - func testSlotAnnotationPropertiesAddedWithoutDuplicate() { - let newSlotProperty = UUID().uuidString - let secondSlotProperty = UUID().uuidString - - manager.slot = newSlotProperty - $displayLink.send() - manager.slot = secondSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, secondSlotProperty) - } - - func testNewSlotPropertyMergedWithAnnotationProperties() { - var annotations = [PointAnnotation]() - for _ in 0...5 { - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.iconAnchor = IconAnchor.testConstantValue() - annotation.iconImage = UUID().uuidString - annotation.iconOffset = [0.0, 0.0] - annotation.iconRotate = 0.0 - annotation.iconSize = 50000.0 - annotation.iconTextFit = IconTextFit.testConstantValue() - annotation.iconTextFitPadding = [0.0, 0.0, 0.0, 0.0] - annotation.symbolSortKey = 0.0 - annotation.textAnchor = TextAnchor.testConstantValue() - annotation.textField = UUID().uuidString - annotation.textJustify = TextJustify.testConstantValue() - annotation.textLetterSpacing = 0.0 - annotation.textLineHeight = 0.0 - annotation.textMaxWidth = 50000.0 - annotation.textOffset = [0.0, 0.0] - annotation.textRadialOffset = 0.0 - annotation.textRotate = 0.0 - annotation.textSize = 50000.0 - annotation.textTransform = TextTransform.testConstantValue() - annotation.iconColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconEmissiveStrength = 50000.0 - annotation.iconHaloBlur = 50000.0 - annotation.iconHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.iconHaloWidth = 50000.0 - annotation.iconImageCrossFade = 0.5 - annotation.iconOcclusionOpacity = 0.5 - annotation.iconOpacity = 0.5 - annotation.textColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textEmissiveStrength = 50000.0 - annotation.textHaloBlur = 50000.0 - annotation.textHaloColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.textHaloWidth = 50000.0 - annotation.textOcclusionOpacity = 0.5 - annotation.textOpacity = 0.5 - annotations.append(annotation) - } - let newSlotProperty = UUID().uuidString - - manager.annotations = annotations - manager.slot = newSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertEqual(manager.impl.layerProperties["slot"] as! String, value) } func testSetToNilSlot() { let newSlotProperty = UUID().uuidString let defaultValue = StyleManager.layerPropertyDefaultValue(for: .symbol, property: "slot").value as! String manager.slot = newSlotProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertNotNil(manager.impl.layerProperties["slot"]) + harness.triggerDisplayLink() manager.slot = nil - $displayLink.send() XCTAssertNil(manager.slot) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) } func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) { @@ -3079,19 +772,19 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega // when manager.annotations = annotations - $displayLink.send() + harness.$displayLink.send() // then - XCTAssertEqual(imagesManager.addImageStub.invocations.count, annotations.count) + XCTAssertEqual(harness.imagesManager.addImageStub.invocations.count, annotations.count) XCTAssertEqual( - Set(imagesManager.addImageStub.invocations.map(\.parameters.id)), + Set(harness.imagesManager.addImageStub.invocations.map(\.parameters.id)), Set(annotations.compactMap(\.image?.name)) ) XCTAssertEqual( - Set(imagesManager.addImageStub.invocations.map(\.parameters.image)), + Set(harness.imagesManager.addImageStub.invocations.map(\.parameters.image)), Set(annotations.compactMap(\.image?.image)) ) - XCTAssertEqual(imagesManager.removeImageStub.invocations.count, 0) + XCTAssertEqual(harness.imagesManager.removeImageStub.invocations.count, 0) XCTAssertTrue(annotations.compactMap(\.image?.name).allSatisfy(manager.isUsingStyleImage(_:))) } @@ -3101,28 +794,28 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega PointAnnotation(image: .init(image: UIImage(), name: UUID().uuidString)) } manager.annotations = allAnnotations - $displayLink.send() - imagesManager.addImageStub.reset() + harness.$displayLink.send() + harness.imagesManager.addImageStub.reset() XCTAssertTrue(allAnnotations.compactMap(\.image?.name).allSatisfy(manager.isUsingStyleImage(_:))) // when let (unusedAnnotations, remainingAnnotations) = (allAnnotations[0..<3], allAnnotations[3...]) manager.annotations = Array(remainingAnnotations) - $displayLink.send() + harness.$displayLink.send() // then - XCTAssertEqual(imagesManager.addImageStub.invocations.count, remainingAnnotations.count) + XCTAssertEqual(harness.imagesManager.addImageStub.invocations.count, remainingAnnotations.count) XCTAssertEqual( - Set(imagesManager.addImageStub.invocations.map(\.parameters.id)), + Set(harness.imagesManager.addImageStub.invocations.map(\.parameters.id)), Set(remainingAnnotations.compactMap(\.image?.name)) ) XCTAssertEqual( - Set(imagesManager.addImageStub.invocations.map(\.parameters.image)), + Set(harness.imagesManager.addImageStub.invocations.map(\.parameters.image)), Set(remainingAnnotations.compactMap(\.image?.image)) ) - XCTAssertEqual(imagesManager.removeImageStub.invocations.count, unusedAnnotations.count) + XCTAssertEqual(harness.imagesManager.removeImageStub.invocations.count, unusedAnnotations.count) XCTAssertEqual( - Set(imagesManager.removeImageStub.invocations.map(\.parameters)), + Set(harness.imagesManager.removeImageStub.invocations.map(\.parameters)), Set(unusedAnnotations.compactMap(\.image?.name)) ) XCTAssertTrue(remainingAnnotations.compactMap(\.image?.name).allSatisfy(manager.isUsingStyleImage(_:))) @@ -3135,25 +828,25 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega .map { _ in PointAnnotation.Image(image: UIImage(), name: UUID().uuidString) } .map(PointAnnotation.init) manager.annotations = annotations - $displayLink.send() + harness.$displayLink.send() // when manager.annotations = [] - $displayLink.send() + harness.$displayLink.send() // then - XCTAssertEqual(imagesManager.addImageStub.invocations.count, annotations.count) + XCTAssertEqual(harness.imagesManager.addImageStub.invocations.count, annotations.count) XCTAssertEqual( - Set(imagesManager.addImageStub.invocations.map(\.parameters.id)), + Set(harness.imagesManager.addImageStub.invocations.map(\.parameters.id)), Set(annotations.compactMap(\.image?.name)) ) XCTAssertEqual( - Set(imagesManager.addImageStub.invocations.map(\.parameters.image)), + Set(harness.imagesManager.addImageStub.invocations.map(\.parameters.image)), Set(annotations.compactMap(\.image?.image)) ) - XCTAssertEqual(imagesManager.removeImageStub.invocations.count, annotations.count) + XCTAssertEqual(harness.imagesManager.removeImageStub.invocations.count, annotations.count) XCTAssertEqual( - Set(imagesManager.removeImageStub.invocations.map(\.parameters)), + Set(harness.imagesManager.removeImageStub.invocations.map(\.parameters)), Set(annotations.compactMap(\.image?.name)) ) XCTAssertTrue(annotations.compactMap(\.image?.name).filter(manager.isUsingStyleImage(_:)).isEmpty) @@ -3165,492 +858,19 @@ final class PointAnnotationManagerTests: XCTestCase, AnnotationInteractionDelega .map { _ in PointAnnotation.Image(image: UIImage(), name: UUID().uuidString) } .map(PointAnnotation.init) manager.annotations = annotations - $displayLink.send() + harness.$displayLink.send() // when - manager.destroy() + manager.impl.destroy() // then - XCTAssertEqual(imagesManager.removeImageStub.invocations.count, annotations.count) + XCTAssertEqual(harness.imagesManager.removeImageStub.invocations.count, annotations.count) XCTAssertEqual( - Set(imagesManager.removeImageStub.invocations.map(\.parameters)), + Set(harness.imagesManager.removeImageStub.invocations.map(\.parameters)), Set(annotations.compactMap(\.image?.name)) ) XCTAssertTrue(annotations.compactMap(\.image?.name).filter(manager.isUsingStyleImage(_:)).isEmpty) } - - // Tests for clustering - func testInitWithDefaultClusterOptions() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - // given - let clusterOptions = ClusterOptions() - var annotations = [PointAnnotation]() - for _ in 0...500 { - let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - - // then - XCTAssertEqual(clusterOptions.clusterRadius, 50) - XCTAssertEqual(clusterOptions.circleRadius, .constant(18)) - XCTAssertEqual(clusterOptions.circleColor, .constant(StyleColor(.black))) - XCTAssertEqual(clusterOptions.textColor, .constant(StyleColor(.white))) - XCTAssertEqual(clusterOptions.textSize, .constant(12)) - XCTAssertEqual(clusterOptions.textField, .expression(Exp(.get) { "point_count" })) - XCTAssertEqual(clusterOptions.clusterMaxZoom, 14) - XCTAssertNil(clusterOptions.clusterProperties) - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.type, SourceType.geoJson) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.id, manager.id) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 3) // symbol layer, one cluster layer, one text layer - XCTAssertNil(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition) - } - - func testSourceClusterOptions() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - // given - let testClusterRadius = Double.testSourceValue() - let testClusterMaxZoom = Double.testSourceValue() - let testClusterProperties = [String: Exp].testSourceValue() - let clusterOptions = ClusterOptions(clusterRadius: testClusterRadius, - clusterMaxZoom: testClusterMaxZoom, - clusterProperties: testClusterProperties) - var annotations = [PointAnnotation]() - for _ in 0...500 { - let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - let geoJSONSource = style.addSourceStub.invocations.last?.parameters.source as! GeoJSONSource - - // then - XCTAssertTrue(geoJSONSource.cluster!) - XCTAssertEqual(clusterOptions.clusterRadius, testClusterRadius) - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(geoJSONSource.clusterRadius, testClusterRadius) - XCTAssertEqual(geoJSONSource.clusterMaxZoom, testClusterMaxZoom) - XCTAssertEqual(geoJSONSource.clusterProperties, testClusterProperties) - } - - func testCircleLayer() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - // given - let testCircleRadius = Value.testConstantValue() - let testCircleColor = Value.testConstantValue() - let clusterOptions = ClusterOptions(circleRadius: testCircleRadius, - circleColor: testCircleColor) - var annotations = [PointAnnotation]() - for _ in 0...500 { - let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - - // then - let circleLayerInvocations = style.addPersistentLayerStub.invocations.filter { circleLayer in - return circleLayer.parameters.layer.id == "mapbox-iOS-cluster-circle-layer-manager-" + id - } - let circleLayer = circleLayerInvocations[0].parameters.layer as! CircleLayer - - XCTAssertEqual(clusterOptions.circleRadius, testCircleRadius) - XCTAssertEqual(circleLayer.circleRadius, testCircleRadius) - XCTAssertEqual(clusterOptions.circleColor, testCircleColor) - XCTAssertEqual(circleLayer.circleColor, testCircleColor) - XCTAssertEqual(circleLayer.filter, Exp(.has) { "point_count" }) - XCTAssertEqual(circleLayer.id, "mapbox-iOS-cluster-circle-layer-manager-" + id) - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - } - - func testTextLayer() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - // given - let testTextColor = Value.testConstantValue() - let testTextSize = Value.testConstantValue() - let testTextField = Value.testConstantValue() - let clusterOptions = ClusterOptions(textColor: testTextColor, - textSize: testTextSize, - textField: testTextField) - var annotations = [PointAnnotation]() - for _ in 0...500 { - let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - - // then - let textLayerInvocations = style.addPersistentLayerStub.invocations.filter { symbolLayer in - return symbolLayer.parameters.layer.id == "mapbox-iOS-cluster-text-layer-manager-" + id - } - let textLayer = textLayerInvocations[0].parameters.layer as! SymbolLayer - - XCTAssertEqual(textLayer.textColor, testTextColor) - XCTAssertEqual(textLayer.textSize, testTextSize) - XCTAssertEqual(textLayer.textField, testTextField) - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - } - - func testSymbolLayers() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - // given - let clusterOptions = ClusterOptions() - var annotations = [PointAnnotation]() - for _ in 0...500 { - let annotation = PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - - // then - let symbolLayerInvocations = style.addPersistentLayerStub.invocations.filter { symbolLayer in - return symbolLayer.parameters.layer.id == id - } - let symbolLayer = symbolLayerInvocations[0].parameters.layer as! SymbolLayer - - XCTAssertTrue(symbolLayer.iconAllowOverlap == .constant(true)) - XCTAssertTrue(symbolLayer.textAllowOverlap == .constant(true)) - XCTAssertTrue(symbolLayer.iconIgnorePlacement == .constant(true)) - XCTAssertTrue(symbolLayer.textIgnorePlacement == .constant(true)) - XCTAssertEqual(symbolLayer.source, id) - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - } - - func testChangeAnnotations() throws { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - // given - let clusterOptions = ClusterOptions() - let annotations = (0..<500).map { _ in - PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - } - let newAnnotations = (0..<100).map { _ in - PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - } - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - $displayLink.send() - let parameters = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last).parameters - XCTAssertEqual(parameters.features, annotations.map(\.feature)) - - // then - pointAnnotationManager.annotations = newAnnotations - $displayLink.send() - let addParameters = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last).parameters - XCTAssertEqual(addParameters.features, newAnnotations.map(\.feature)) - - let removeParameters = try XCTUnwrap(style.removeGeoJSONSourceFeaturesStub.invocations.last).parameters - XCTAssertEqual(removeParameters.featureIds, annotations.map(\.id)) - } - - func testDestroyAnnotationManager() { - // given - let clusterOptions = ClusterOptions() - - // when - let pointAnnotationManager = PointAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - clusterOptions: clusterOptions, - mapFeatureQueryable: mapFeatureQueryable, - imagesManager: imagesManager, - offsetCalculator: offsetCalculator - ) - pointAnnotationManager.annotations = annotations - pointAnnotationManager.destroy() - - let removeLayerInvocations = style.removeLayerStub.invocations - - // then - XCTAssertEqual(removeLayerInvocations.map(\.parameters), [ - "mapbox-iOS-cluster-circle-layer-manager-" + id, - "mapbox-iOS-cluster-text-layer-manager-" + id, - id, - ]) - } - - func testGetAnnotations() { - let annotations = Array.random(withLength: 10) { - PointAnnotation(coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) - } - manager.annotations = annotations - - // Dragged annotation will be added to internal list of dragged annotations. - let annotationToDrag = annotations.randomElement()! - _ = manager.handleDragBegin(with: annotationToDrag.id, context: .zero) - XCTAssertTrue(manager.annotations.contains(where: { $0.id == annotationToDrag.id })) - } - - func testHandleDragBeginIsDraggableFalse() throws { - manager.annotations = [ - PointAnnotation(id: "point1", coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: false) - ] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "point1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 0) - } - func testHandleDragBeginInvalidFeatureId() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "not-a-feature", context: .zero) - - XCTAssertTrue(style.addSourceStub.invocations.isEmpty) - XCTAssertTrue(style.addPersistentLayerStub.invocations.isEmpty) - } - - func testDrag() throws { - let annotation = PointAnnotation(id: "point1", coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) - manager.annotations = [annotation] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - _ = manager.handleDragBegin(with: "point1", context: .zero) - - let addSourceParameters = try XCTUnwrap(style.addSourceStub.invocations.last).parameters - let addLayerParameters = try XCTUnwrap(style.addPersistentLayerStub.invocations.last).parameters - - let addedLayer = try XCTUnwrap(addLayerParameters.layer as? SymbolLayer) - XCTAssertEqual(addedLayer.source, addSourceParameters.source.id) - XCTAssertEqual(addLayerParameters.layerPosition, .above(manager.id)) - XCTAssertEqual(addedLayer.id, manager.id + "_drag") - - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 1) - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.last?.parameters.id, "\(manager.id)_drag") - - _ = manager.handleDragBegin(with: "point1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 1) - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 0, longitude: 0) - mapboxMap.cameraState.zoom = 1 - - manager.handleDragChange(with: .zero, context: .zero) - - $displayLink.send() - - let updateSourceParameters = try XCTUnwrap(style.updateGeoJSONSourceStub.invocations.last).parameters - XCTAssertTrue(updateSourceParameters.id == addSourceParameters.source.id) - if case .featureCollection(let collection) = updateSourceParameters.geojson { - XCTAssertTrue(collection.features.contains(where: { $0.identifier?.rawValue as? String == annotation.id })) - } else { - XCTFail("GeoJSONObject should be a feature collection") - } - } - - func testDragHandlers() throws { - struct GestureData { - var annotation: PointAnnotation - var context: MapContentGestureContext - } - - var annotation = PointAnnotation(point: .init(.init(latitude: 0, longitude: 0)), isSelected: false, isDraggable: false) - annotation.isDraggable = true - - let beginDragStub = Stub(defaultReturnValue: false) - let changeDragStub = Stub() - let endDragStub = Stub() - annotation.dragBeginHandler = { annotation, context in - beginDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragChangeHandler = { annotation, context in - changeDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragEndHandler = { annotation, context in - endDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - manager.annotations = [annotation] - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 23.5432356, longitude: -12.5326744) - mapboxMap.cameraState.zoom = 1 - - var context = MapContentGestureContext(point: CGPoint(x: 0, y: 1), coordinate: .init(latitude: 2, longitude: 3)) - - // test it twice to cover the case when annotation was already on drag layer. - for _ in 0...1 { - beginDragStub.reset() - changeDragStub.reset() - endDragStub.reset() - - // skipped gesture - beginDragStub.defaultReturnValue = false - var res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 1) - XCTAssertEqual(res, false) - var data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - manager.handleDragEnd(context: context) - XCTAssertEqual(changeDragStub.invocations.count, 0) - XCTAssertEqual(endDragStub.invocations.count, 0) - - // handled gesture - context.point.x += 1 - context.coordinate.latitude += 1 - beginDragStub.defaultReturnValue = true - res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 2) - XCTAssertEqual(res, true) - data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - XCTAssertEqual(changeDragStub.invocations.count, 1) - data = try XCTUnwrap(changeDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragEnd(context: context) - XCTAssertEqual(endDragStub.invocations.count, 1) - data = try XCTUnwrap(endDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - } - } - - func testDoesNotUpdateDragSourceWhenNoDragged() { - let annotation = PointAnnotation(id: "point1", coordinate: .init(latitude: 0, longitude: 0), isSelected: false, isDraggable: true) - manager.annotations = [annotation] - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - } - - func testRemovingDuplicatedAnnotations() { - let annotation1 = PointAnnotation(id: "A", point: .init(.init(latitude: 1, longitude: 1)), isSelected: false, isDraggable: false) - let annotation2 = PointAnnotation(id: "B", point: .init(.init(latitude: 2, longitude: 2)), isSelected: false, isDraggable: false) - let annotation3 = PointAnnotation(id: "A", point: .init(.init(latitude: 3, longitude: 3)), isSelected: false, isDraggable: false) - manager.annotations = [annotation1, annotation2, annotation3] - - XCTAssertEqual(manager.annotations, [ - annotation1, - annotation2 - ]) - } - - func testSetNewAnnotations() { - let annotation1 = PointAnnotation(id: "A", point: .init(.init(latitude: 1, longitude: 1)), isSelected: false, isDraggable: false) - let annotation2 = PointAnnotation(id: "B", point: .init(.init(latitude: 2, longitude: 2)), isSelected: false, isDraggable: false) - let annotation3 = PointAnnotation(id: "C", point: .init(.init(latitude: 3, longitude: 3)), isSelected: false, isDraggable: false) - - manager.set(newAnnotations: [ - (1, annotation1), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (1, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (3, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["C", "B"]) - } } private extension PointAnnotation { diff --git a/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationIntegrationTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationIntegrationTests.swift index d19d98cb29b7..d9fe73da8191 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationIntegrationTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationIntegrationTests.swift @@ -24,7 +24,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { } func testSourceAndLayerRemovedUponDestroy() { - manager.destroy() + manager.impl.destroy() XCTAssertFalse(mapView.mapboxMap.allLayerIdentifiers.map { $0.id }.contains(manager.layerId)) XCTAssertFalse(mapView.mapboxMap.allSourceIdentifiers.map { $0.id }.contains(manager.sourceId)) @@ -75,7 +75,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.fillAntialias, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) if case .constant(let actualValue) = layer.fillAntialias { XCTAssertEqual(actualValue, value) @@ -89,7 +89,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillAntialias, .constant((StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-antialias").value as! NSNumber).boolValue)) } @@ -101,7 +101,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.fillEmissiveStrength, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) if case .constant(let actualValue) = layer.fillEmissiveStrength { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -115,7 +115,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillEmissiveStrength, .constant((StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-emissive-strength").value as! NSNumber).doubleValue)) } @@ -127,7 +127,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.fillTranslate, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) if case .constant(let actualValue) = layer.fillTranslate { for (actual, expected) in zip(actualValue, value) { @@ -143,7 +143,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillTranslate, .constant(StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-translate").value as! [Double])) } @@ -155,7 +155,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.fillTranslateAnchor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) if case .constant(let actualValue) = layer.fillTranslateAnchor { XCTAssertEqual(actualValue, value) @@ -169,7 +169,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillTranslateAnchor, .constant(FillTranslateAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-translate-anchor").value as! String))) } @@ -181,7 +181,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.slot, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) let actualValue = layer.slot?.rawValue ?? "" XCTAssertEqual(actualValue, value) @@ -192,7 +192,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.slot, nil) } @@ -214,7 +214,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillSortKey, .expression(Exp(.number) { Exp(.get) { @@ -235,7 +235,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillSortKey, .constant((StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-sort-key").value as! NSNumber).doubleValue)) } @@ -257,7 +257,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillColor, .expression(Exp(.toColor) { Exp(.get) { @@ -278,7 +278,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-color").value as! [Any], options: [])))) } @@ -300,7 +300,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillOpacity, .expression(Exp(.number) { Exp(.get) { @@ -321,7 +321,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-opacity").value as! NSNumber).doubleValue)) } @@ -343,7 +343,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillOutlineColor, .expression(Exp(.toColor) { Exp(.get) { @@ -364,7 +364,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillOutlineColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-outline-color").value as! [Any], options: [])))) } @@ -386,7 +386,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillPattern, .expression(Exp(.image) { Exp(.get) { @@ -407,7 +407,7 @@ final class PolygonAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: FillLayer.self) XCTAssertEqual(layer.fillPattern, .constant(.name(StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-pattern").value as! String))) } diff --git a/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationManagerTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationManagerTests.swift index 790d3fbfae02..aceb8b4b4a86 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationManagerTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/PolygonAnnotationManagerTests.swift @@ -4,28 +4,18 @@ import XCTest final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDelegate { var manager: PolygonAnnotationManager! - var style: MockStyle! - var id = UUID().uuidString + var harness: AnnotationManagerTestingHarness! var annotations = [PolygonAnnotation]() var expectation: XCTestExpectation? var delegateAnnotations: [Annotation]? - var offsetCalculator: OffsetPolygonCalculator! - var mapboxMap: MockMapboxMap! - @TestSignal var displayLink: Signal override func setUp() { super.setUp() - style = MockStyle() - mapboxMap = MockMapboxMap() - offsetCalculator = OffsetPolygonCalculator(mapboxMap: mapboxMap) + harness = AnnotationManagerTestingHarness() manager = PolygonAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) + params: harness.makeParams(), + deps: harness.makeDeps()) for _ in 0...10 { let polygonCoords = [ @@ -41,244 +31,11 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele } override func tearDown() { - style = nil - expectation = nil - delegateAnnotations = nil - mapboxMap = nil - offsetCalculator = nil + harness = nil manager = nil - super.tearDown() } - func testSourceSetup() { - style.addSourceStub.reset() - - _ = PolygonAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.type, SourceType.geoJson) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.id, manager.id) - } - - func testAddLayer() throws { - style.addSourceStub.reset() - let initializedManager = PolygonAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerWithPropertiesStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.type, LayerType.fill) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.id, initializedManager.id) - let addedLayer = try XCTUnwrap(style.addPersistentLayerStub.invocations.last?.parameters.layer as? FillLayer) - XCTAssertEqual(addedLayer.source, initializedManager.sourceId) - XCTAssertNil(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition) - } - - func testAddManagerWithDuplicateId() { - var annotations2 = [PolygonAnnotation]() - for _ in 0...50 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - let annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotations2.append(annotation) - } - - manager.annotations = annotations - let manager2 = PolygonAnnotationManager( - id: manager.id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - manager2.annotations = annotations2 - - XCTAssertEqual(manager.annotations.count, 11) - XCTAssertEqual(manager2.annotations.count, 51) - } - - func testLayerPositionPassedCorrectly() { - let manager3 = PolygonAnnotationManager( - id: id, - style: style, - layerPosition: LayerPosition.at(4), - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - manager3.annotations = annotations - - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition, LayerPosition.at(4)) - } - - func testDestroy() { - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testDestroyManagerWithDraggedAnnotations() { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.isDraggable = true - manager.annotations = [annotation] - // adds drag source/layer - _ = manager.handleDragBegin(with: annotation.id, context: .zero) - - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id, id + "_drag"]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id, id + "_drag"]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testSyncSourceAndLayer() { - manager.annotations = annotations - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - } - - func testDoNotSyncSourceAndLayerWhenNotNeeded() { - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 0) - } - - func testFeatureCollectionPassedtoGeoJSON() throws { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - let annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - let expectedFeatures = annotations.map(\.feature) - - manager.annotations = annotations - $displayLink.send() - - var invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, expectedFeatures) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - - do { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - let annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotations.append(annotation) - - manager.annotations = annotations - $displayLink.send() - - invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, [annotation].map(\.feature)) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - } - } - - @available(*, deprecated) - func testHandleTap() throws { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - let annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - var taps = [MapContentGestureContext]() - annotations[0].tapHandler = { context in - taps.append(context) - return true - } - annotations[1].tapHandler = { _ in - return false // skips handling - } - manager.delegate = self - - manager.annotations = annotations - - // first annotation, handles tap - let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) - var handled = manager.handleTap(layerId: "layerId", feature: annotations[0].feature, context: context) - - var result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[0].id) - XCTAssertEqual(handled, true) - - XCTAssertEqual(taps.count, 1) - XCTAssertEqual(taps.first?.point, context.point) - XCTAssertEqual(taps.first?.coordinate, context.coordinate) - - // second annotation, skips handling tap - delegateAnnotations = nil - handled = manager.handleTap(layerId: "layerId", feature: annotations[1].feature, context: context) - - result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[1].id) - XCTAssertEqual(handled, false) - - // invalid id - delegateAnnotations = nil - let invalidFeature = Feature(geometry: nil) - handled = manager.handleTap(layerId: "layerId", feature: invalidFeature, context: context) - - XCTAssertNil(delegateAnnotations) - XCTAssertEqual(handled, false) - XCTAssertEqual(taps.count, 1) - } - func testInitialFillAntialias() { let initialValue = manager.fillAntialias XCTAssertNil(initialValue) @@ -288,71 +45,22 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele let value = true manager.fillAntialias = value XCTAssertEqual(manager.fillAntialias, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-antialias"] as! Bool, value) - } - - func testFillAntialiasAnnotationPropertiesAddedWithoutDuplicate() { - let newFillAntialiasProperty = true - let secondFillAntialiasProperty = true - - manager.fillAntialias = newFillAntialiasProperty - $displayLink.send() - manager.fillAntialias = secondFillAntialiasProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-antialias"] as! Bool, secondFillAntialiasProperty) - } - - func testNewFillAntialiasPropertyMergedWithAnnotationProperties() { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.fillSortKey = 0.0 - annotation.fillColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillOpacity = 0.5 - annotation.fillOutlineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillPattern = UUID().uuidString - annotations.append(annotation) - } - let newFillAntialiasProperty = true - - manager.annotations = annotations - manager.fillAntialias = newFillAntialiasProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-antialias"]) + XCTAssertEqual(manager.impl.layerProperties["fill-antialias"] as! Bool, value) } func testSetToNilFillAntialias() { let newFillAntialiasProperty = true let defaultValue = StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-antialias").value as! Bool manager.fillAntialias = newFillAntialiasProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-antialias"]) + XCTAssertNotNil(manager.impl.layerProperties["fill-antialias"]) + harness.triggerDisplayLink() manager.fillAntialias = nil - $displayLink.send() XCTAssertNil(manager.fillAntialias) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-antialias"] as! Bool, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-antialias"] as! Bool, defaultValue) } - func testInitialFillEmissiveStrength() { let initialValue = manager.fillEmissiveStrength XCTAssertNil(initialValue) @@ -362,71 +70,22 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele let value = 50000.0 manager.fillEmissiveStrength = value XCTAssertEqual(manager.fillEmissiveStrength, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-emissive-strength"] as! Double, value) - } - - func testFillEmissiveStrengthAnnotationPropertiesAddedWithoutDuplicate() { - let newFillEmissiveStrengthProperty = 50000.0 - let secondFillEmissiveStrengthProperty = 50000.0 - - manager.fillEmissiveStrength = newFillEmissiveStrengthProperty - $displayLink.send() - manager.fillEmissiveStrength = secondFillEmissiveStrengthProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-emissive-strength"] as! Double, secondFillEmissiveStrengthProperty) - } - - func testNewFillEmissiveStrengthPropertyMergedWithAnnotationProperties() { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.fillSortKey = 0.0 - annotation.fillColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillOpacity = 0.5 - annotation.fillOutlineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillPattern = UUID().uuidString - annotations.append(annotation) - } - let newFillEmissiveStrengthProperty = 50000.0 - - manager.annotations = annotations - manager.fillEmissiveStrength = newFillEmissiveStrengthProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-emissive-strength"]) + XCTAssertEqual(manager.impl.layerProperties["fill-emissive-strength"] as! Double, value) } func testSetToNilFillEmissiveStrength() { let newFillEmissiveStrengthProperty = 50000.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-emissive-strength").value as! Double manager.fillEmissiveStrength = newFillEmissiveStrengthProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-emissive-strength"]) + XCTAssertNotNil(manager.impl.layerProperties["fill-emissive-strength"]) + harness.triggerDisplayLink() manager.fillEmissiveStrength = nil - $displayLink.send() XCTAssertNil(manager.fillEmissiveStrength) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-emissive-strength"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-emissive-strength"] as! Double, defaultValue) } - func testInitialFillTranslate() { let initialValue = manager.fillTranslate XCTAssertNil(initialValue) @@ -436,71 +95,22 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele let value = [0.0, 0.0] manager.fillTranslate = value XCTAssertEqual(manager.fillTranslate, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate"] as! [Double], value) - } - - func testFillTranslateAnnotationPropertiesAddedWithoutDuplicate() { - let newFillTranslateProperty = [0.0, 0.0] - let secondFillTranslateProperty = [0.0, 0.0] - - manager.fillTranslate = newFillTranslateProperty - $displayLink.send() - manager.fillTranslate = secondFillTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate"] as! [Double], secondFillTranslateProperty) - } - - func testNewFillTranslatePropertyMergedWithAnnotationProperties() { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.fillSortKey = 0.0 - annotation.fillColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillOpacity = 0.5 - annotation.fillOutlineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillPattern = UUID().uuidString - annotations.append(annotation) - } - let newFillTranslateProperty = [0.0, 0.0] - - manager.annotations = annotations - manager.fillTranslate = newFillTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate"]) + XCTAssertEqual(manager.impl.layerProperties["fill-translate"] as! [Double], value) } func testSetToNilFillTranslate() { let newFillTranslateProperty = [0.0, 0.0] let defaultValue = StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-translate").value as! [Double] manager.fillTranslate = newFillTranslateProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate"]) + XCTAssertNotNil(manager.impl.layerProperties["fill-translate"]) + harness.triggerDisplayLink() manager.fillTranslate = nil - $displayLink.send() XCTAssertNil(manager.fillTranslate) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate"] as! [Double], defaultValue) } - func testInitialFillTranslateAnchor() { let initialValue = manager.fillTranslateAnchor XCTAssertNil(initialValue) @@ -510,71 +120,22 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele let value = FillTranslateAnchor.testConstantValue() manager.fillTranslateAnchor = value XCTAssertEqual(manager.fillTranslateAnchor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate-anchor"] as! String, value.rawValue) - } - - func testFillTranslateAnchorAnnotationPropertiesAddedWithoutDuplicate() { - let newFillTranslateAnchorProperty = FillTranslateAnchor.testConstantValue() - let secondFillTranslateAnchorProperty = FillTranslateAnchor.testConstantValue() - - manager.fillTranslateAnchor = newFillTranslateAnchorProperty - $displayLink.send() - manager.fillTranslateAnchor = secondFillTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate-anchor"] as! String, secondFillTranslateAnchorProperty.rawValue) - } - - func testNewFillTranslateAnchorPropertyMergedWithAnnotationProperties() { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.fillSortKey = 0.0 - annotation.fillColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillOpacity = 0.5 - annotation.fillOutlineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillPattern = UUID().uuidString - annotations.append(annotation) - } - let newFillTranslateAnchorProperty = FillTranslateAnchor.testConstantValue() - - manager.annotations = annotations - manager.fillTranslateAnchor = newFillTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate-anchor"]) + XCTAssertEqual(manager.impl.layerProperties["fill-translate-anchor"] as! String, value.rawValue) } func testSetToNilFillTranslateAnchor() { let newFillTranslateAnchorProperty = FillTranslateAnchor.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .fill, property: "fill-translate-anchor").value as! String manager.fillTranslateAnchor = newFillTranslateAnchorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate-anchor"]) + XCTAssertNotNil(manager.impl.layerProperties["fill-translate-anchor"]) + harness.triggerDisplayLink() manager.fillTranslateAnchor = nil - $displayLink.send() XCTAssertNil(manager.fillTranslateAnchor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate-anchor"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["fill-translate-anchor"] as! String, defaultValue) } - func testInitialSlot() { let initialValue = manager.slot XCTAssertNil(initialValue) @@ -584,69 +145,21 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele let value = UUID().uuidString manager.slot = value XCTAssertEqual(manager.slot, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, value) - } - - func testSlotAnnotationPropertiesAddedWithoutDuplicate() { - let newSlotProperty = UUID().uuidString - let secondSlotProperty = UUID().uuidString - - manager.slot = newSlotProperty - $displayLink.send() - manager.slot = secondSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, secondSlotProperty) - } - - func testNewSlotPropertyMergedWithAnnotationProperties() { - var annotations = [PolygonAnnotation]() - for _ in 0...5 { - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.fillSortKey = 0.0 - annotation.fillColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillOpacity = 0.5 - annotation.fillOutlineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.fillPattern = UUID().uuidString - annotations.append(annotation) - } - let newSlotProperty = UUID().uuidString - - manager.annotations = annotations - manager.slot = newSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertEqual(manager.impl.layerProperties["slot"] as! String, value) } func testSetToNilSlot() { let newSlotProperty = UUID().uuidString let defaultValue = StyleManager.layerPropertyDefaultValue(for: .fill, property: "slot").value as! String manager.slot = newSlotProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertNotNil(manager.impl.layerProperties["slot"]) + harness.triggerDisplayLink() manager.slot = nil - $displayLink.send() XCTAssertNil(manager.slot) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) } func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) { @@ -655,281 +168,6 @@ final class PolygonAnnotationManagerTests: XCTestCase, AnnotationInteractionDele expectation = nil } - func testGetAnnotations() { - let annotations = Array.random(withLength: 10) { - PolygonAnnotation( - polygon: .init(outerRing: Ring(coordinates: .random(withLength: 5, generator: { CLLocationCoordinate2D(latitude: 0, longitude: 0) }))), - isSelected: false, - isDraggable: true) - } - manager.annotations = annotations - - // Dragged annotation will be added to internal list of dragged annotations. - let annotationToDrag = annotations.randomElement()! - _ = manager.handleDragBegin(with: annotationToDrag.id, context: .zero) - XCTAssertTrue(manager.annotations.contains(where: { $0.id == annotationToDrag.id })) - } - - func testHandleDragBeginIsDraggableFalse() throws { - manager.annotations = [ - PolygonAnnotation(id: "polygon1", polygon: .init([[ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ]]), isSelected: false, isDraggable: false) - ] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "polygon1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 0) - } - func testHandleDragBeginInvalidFeatureId() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "not-a-feature", context: .zero) - - XCTAssertTrue(style.addSourceStub.invocations.isEmpty) - XCTAssertTrue(style.addPersistentLayerStub.invocations.isEmpty) - } - - func testDrag() throws { - let annotation = PolygonAnnotation(id: "polygon1", polygon: .init([[ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ]]), isSelected: false, isDraggable: true) - manager.annotations = [annotation] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - _ = manager.handleDragBegin(with: "polygon1", context: .zero) - - let addSourceParameters = try XCTUnwrap(style.addSourceStub.invocations.last).parameters - let addLayerParameters = try XCTUnwrap(style.addPersistentLayerStub.invocations.last).parameters - - let addedLayer = try XCTUnwrap(addLayerParameters.layer as? FillLayer) - XCTAssertEqual(addedLayer.source, addSourceParameters.source.id) - XCTAssertEqual(addLayerParameters.layerPosition, .above(manager.id)) - XCTAssertEqual(addedLayer.id, manager.id + "_drag") - - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 1) - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.last?.parameters.id, "\(manager.id)_drag") - - _ = manager.handleDragBegin(with: "polygon1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 1) - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 0, longitude: 0) - mapboxMap.cameraState.zoom = 1 - - manager.handleDragChange(with: .zero, context: .zero) - - $displayLink.send() - - let updateSourceParameters = try XCTUnwrap(style.updateGeoJSONSourceStub.invocations.last).parameters - XCTAssertTrue(updateSourceParameters.id == addSourceParameters.source.id) - if case .featureCollection(let collection) = updateSourceParameters.geojson { - XCTAssertTrue(collection.features.contains(where: { $0.identifier?.rawValue as? String == annotation.id })) - } else { - XCTFail("GeoJSONObject should be a feature collection") - } - } - - func testDragHandlers() throws { - struct GestureData { - var annotation: PolygonAnnotation - var context: MapContentGestureContext - } - - let polygonCoords = [ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ] - var annotation = PolygonAnnotation(polygon: .init(outerRing: .init(coordinates: polygonCoords)), isSelected: false, isDraggable: false) - annotation.isDraggable = true - - let beginDragStub = Stub(defaultReturnValue: false) - let changeDragStub = Stub() - let endDragStub = Stub() - annotation.dragBeginHandler = { annotation, context in - beginDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragChangeHandler = { annotation, context in - changeDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragEndHandler = { annotation, context in - endDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - manager.annotations = [annotation] - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 23.5432356, longitude: -12.5326744) - mapboxMap.cameraState.zoom = 1 - - var context = MapContentGestureContext(point: CGPoint(x: 0, y: 1), coordinate: .init(latitude: 2, longitude: 3)) - - // test it twice to cover the case when annotation was already on drag layer. - for _ in 0...1 { - beginDragStub.reset() - changeDragStub.reset() - endDragStub.reset() - - // skipped gesture - beginDragStub.defaultReturnValue = false - var res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 1) - XCTAssertEqual(res, false) - var data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - manager.handleDragEnd(context: context) - XCTAssertEqual(changeDragStub.invocations.count, 0) - XCTAssertEqual(endDragStub.invocations.count, 0) - - // handled gesture - context.point.x += 1 - context.coordinate.latitude += 1 - beginDragStub.defaultReturnValue = true - res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 2) - XCTAssertEqual(res, true) - data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - XCTAssertEqual(changeDragStub.invocations.count, 1) - data = try XCTUnwrap(changeDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragEnd(context: context) - XCTAssertEqual(endDragStub.invocations.count, 1) - data = try XCTUnwrap(endDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - } - } - - func testDoesNotUpdateDragSourceWhenNoDragged() { - let annotation = PolygonAnnotation(id: "polygon1", polygon: .init([[ - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -87.967529296875), - CLLocationCoordinate2DMake(26.244156283890756, -89.857177734375), - CLLocationCoordinate2DMake(24.51713945052515, -89.857177734375) - ]]), isSelected: false, isDraggable: true) - manager.annotations = [annotation] - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - } - - func testRemovingDuplicatedAnnotations() { - let polygonCoords1 = [ - CLLocationCoordinate2DMake(25.51713945052515, -88.857177734375), - CLLocationCoordinate2DMake(25.51713945052515, -86.967529296875), - CLLocationCoordinate2DMake(27.244156283890756, -86.967529296875), - CLLocationCoordinate2DMake(27.244156283890756, -88.857177734375), - CLLocationCoordinate2DMake(25.51713945052515, -88.857177734375) - ] - let annotation1 = PolygonAnnotation(id: "A", polygon: .init(outerRing: .init(coordinates: polygonCoords1)), isSelected: false, isDraggable: false) - let polygonCoords2 = [ - CLLocationCoordinate2DMake(26.51713945052515, -87.857177734375), - CLLocationCoordinate2DMake(26.51713945052515, -85.967529296875), - CLLocationCoordinate2DMake(28.244156283890756, -85.967529296875), - CLLocationCoordinate2DMake(28.244156283890756, -87.857177734375), - CLLocationCoordinate2DMake(26.51713945052515, -87.857177734375) - ] - let annotation2 = PolygonAnnotation(id: "B", polygon: .init(outerRing: .init(coordinates: polygonCoords2)), isSelected: false, isDraggable: false) - let polygonCoords3 = [ - CLLocationCoordinate2DMake(27.51713945052515, -86.857177734375), - CLLocationCoordinate2DMake(27.51713945052515, -84.967529296875), - CLLocationCoordinate2DMake(29.244156283890756, -84.967529296875), - CLLocationCoordinate2DMake(29.244156283890756, -86.857177734375), - CLLocationCoordinate2DMake(27.51713945052515, -86.857177734375) - ] - let annotation3 = PolygonAnnotation(id: "A", polygon: .init(outerRing: .init(coordinates: polygonCoords3)), isSelected: false, isDraggable: false) - manager.annotations = [annotation1, annotation2, annotation3] - - XCTAssertEqual(manager.annotations, [ - annotation1, - annotation2 - ]) - } - - func testSetNewAnnotations() { - let polygonCoords1 = [ - CLLocationCoordinate2DMake(25.51713945052515, -88.857177734375), - CLLocationCoordinate2DMake(25.51713945052515, -86.967529296875), - CLLocationCoordinate2DMake(27.244156283890756, -86.967529296875), - CLLocationCoordinate2DMake(27.244156283890756, -88.857177734375), - CLLocationCoordinate2DMake(25.51713945052515, -88.857177734375) - ] - let annotation1 = PolygonAnnotation(id: "A", polygon: .init(outerRing: .init(coordinates: polygonCoords1)), isSelected: false, isDraggable: false) - let polygonCoords2 = [ - CLLocationCoordinate2DMake(26.51713945052515, -87.857177734375), - CLLocationCoordinate2DMake(26.51713945052515, -85.967529296875), - CLLocationCoordinate2DMake(28.244156283890756, -85.967529296875), - CLLocationCoordinate2DMake(28.244156283890756, -87.857177734375), - CLLocationCoordinate2DMake(26.51713945052515, -87.857177734375) - ] - let annotation2 = PolygonAnnotation(id: "B", polygon: .init(outerRing: .init(coordinates: polygonCoords2)), isSelected: false, isDraggable: false) - let polygonCoords3 = [ - CLLocationCoordinate2DMake(27.51713945052515, -86.857177734375), - CLLocationCoordinate2DMake(27.51713945052515, -84.967529296875), - CLLocationCoordinate2DMake(29.244156283890756, -84.967529296875), - CLLocationCoordinate2DMake(29.244156283890756, -86.857177734375), - CLLocationCoordinate2DMake(27.51713945052515, -86.857177734375) - ] - let annotation3 = PolygonAnnotation(id: "C", polygon: .init(outerRing: .init(coordinates: polygonCoords3)), isSelected: false, isDraggable: false) - - manager.set(newAnnotations: [ - (1, annotation1), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (1, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (3, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["C", "B"]) - } } // End of generated file diff --git a/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationIntegrationTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationIntegrationTests.swift index eec4c48d71b2..caca942783f1 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationIntegrationTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationIntegrationTests.swift @@ -24,7 +24,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { } func testSourceAndLayerRemovedUponDestroy() { - manager.destroy() + manager.impl.destroy() XCTAssertFalse(mapView.mapboxMap.allLayerIdentifiers.map { $0.id }.contains(manager.layerId)) XCTAssertFalse(mapView.mapboxMap.allSourceIdentifiers.map { $0.id }.contains(manager.sourceId)) @@ -69,7 +69,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineCap, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineCap { XCTAssertEqual(actualValue, value) @@ -83,7 +83,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineCap, .constant(LineCap(rawValue: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-cap").value as! String))) } @@ -95,7 +95,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineMiterLimit, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineMiterLimit { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -109,7 +109,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineMiterLimit, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-miter-limit").value as! NSNumber).doubleValue)) } @@ -121,7 +121,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineRoundLimit, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineRoundLimit { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -135,7 +135,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineRoundLimit, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-round-limit").value as! NSNumber).doubleValue)) } @@ -147,7 +147,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineDasharray, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineDasharray { for (actual, expected) in zip(actualValue, value) { @@ -163,7 +163,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineDasharray, .constant(StyleManager.layerPropertyDefaultValue(for: .line, property: "line-dasharray").value as! [Double])) } @@ -175,7 +175,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineDepthOcclusionFactor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineDepthOcclusionFactor { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -189,7 +189,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineDepthOcclusionFactor, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-depth-occlusion-factor").value as! NSNumber).doubleValue)) } @@ -201,7 +201,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineEmissiveStrength, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineEmissiveStrength { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -215,7 +215,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineEmissiveStrength, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-emissive-strength").value as! NSNumber).doubleValue)) } @@ -227,7 +227,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineOcclusionOpacity, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineOcclusionOpacity { XCTAssertEqual(actualValue, value, accuracy: 0.1) @@ -241,7 +241,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineOcclusionOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-occlusion-opacity").value as! NSNumber).doubleValue)) } @@ -253,7 +253,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineTranslate, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineTranslate { for (actual, expected) in zip(actualValue, value) { @@ -269,7 +269,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineTranslate, .constant(StyleManager.layerPropertyDefaultValue(for: .line, property: "line-translate").value as! [Double])) } @@ -281,7 +281,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineTranslateAnchor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineTranslateAnchor { XCTAssertEqual(actualValue, value) @@ -295,7 +295,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineTranslateAnchor, .constant(LineTranslateAnchor(rawValue: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-translate-anchor").value as! String))) } @@ -307,7 +307,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineTrimColor, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineTrimColor { XCTAssertEqual(actualValue, value) @@ -321,7 +321,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineTrimColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-trim-color").value as! [Any], options: [])))) } @@ -333,7 +333,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineTrimFadeRange, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineTrimFadeRange { for (actual, expected) in zip(actualValue, value) { @@ -349,7 +349,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineTrimFadeRange, .constant(StyleManager.layerPropertyDefaultValue(for: .line, property: "line-trim-fade-range").value as! [Double])) } @@ -361,7 +361,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.lineTrimOffset, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) if case .constant(let actualValue) = layer.lineTrimOffset { for (actual, expected) in zip(actualValue, value) { @@ -377,7 +377,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineTrimOffset, .constant(StyleManager.layerPropertyDefaultValue(for: .line, property: "line-trim-offset").value as! [Double])) } @@ -389,7 +389,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { XCTAssertEqual(manager.slot, value) // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) let actualValue = layer.slot?.rawValue ?? "" XCTAssertEqual(actualValue, value) @@ -400,7 +400,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.slot, nil) } @@ -416,7 +416,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineJoin, .expression(Exp(.toString) { Exp(.get) { @@ -437,7 +437,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineJoin, .constant(LineJoin(rawValue: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-join").value as! String))) } @@ -453,7 +453,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineSortKey, .expression(Exp(.number) { Exp(.get) { @@ -474,7 +474,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineSortKey, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-sort-key").value as! NSNumber).doubleValue)) } @@ -490,7 +490,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineZOffset, .expression(Exp(.number) { Exp(.get) { @@ -511,7 +511,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineZOffset, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-z-offset").value as! NSNumber).doubleValue)) } @@ -527,7 +527,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineBlur, .expression(Exp(.number) { Exp(.get) { @@ -548,7 +548,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineBlur, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-blur").value as! NSNumber).doubleValue)) } @@ -564,7 +564,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineBorderColor, .expression(Exp(.toColor) { Exp(.get) { @@ -585,7 +585,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineBorderColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-border-color").value as! [Any], options: [])))) } @@ -601,7 +601,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineBorderWidth, .expression(Exp(.number) { Exp(.get) { @@ -622,7 +622,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineBorderWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-border-width").value as! NSNumber).doubleValue)) } @@ -638,7 +638,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineColor, .expression(Exp(.toColor) { Exp(.get) { @@ -659,7 +659,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineColor, .constant(try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-color").value as! [Any], options: [])))) } @@ -675,7 +675,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineGapWidth, .expression(Exp(.number) { Exp(.get) { @@ -696,7 +696,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineGapWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-gap-width").value as! NSNumber).doubleValue)) } @@ -712,7 +712,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineOffset, .expression(Exp(.number) { Exp(.get) { @@ -733,7 +733,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineOffset, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-offset").value as! NSNumber).doubleValue)) } @@ -749,7 +749,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineOpacity, .expression(Exp(.number) { Exp(.get) { @@ -770,7 +770,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineOpacity, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-opacity").value as! NSNumber).doubleValue)) } @@ -786,7 +786,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.linePattern, .expression(Exp(.image) { Exp(.get) { @@ -807,7 +807,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.linePattern, .constant(.name(StyleManager.layerPropertyDefaultValue(for: .line, property: "line-pattern").value as! String))) } @@ -823,7 +823,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { manager.annotations = [annotation] // Test that the value is synced to the layer - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() var layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineWidth, .expression(Exp(.number) { Exp(.get) { @@ -844,7 +844,7 @@ final class PolylineAnnotationIntegrationTests: MapViewIntegrationTestCase { // Verify that when the property is reset to nil, // the layer is returned to the default value - manager.syncSourceAndLayerIfNeeded() + manager.impl.syncSourceAndLayerIfNeeded() layer = try mapView.mapboxMap.layer(withId: self.manager.layerId, type: LineLayer.self) XCTAssertEqual(layer.lineWidth, .constant((StyleManager.layerPropertyDefaultValue(for: .line, property: "line-width").value as! NSNumber).doubleValue)) } diff --git a/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationManagerTests.swift b/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationManagerTests.swift index 96b2935bfee6..617ce73ad326 100644 --- a/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationManagerTests.swift +++ b/Tests/MapboxMapsTests/Annotations/Generated/PolylineAnnotationManagerTests.swift @@ -4,28 +4,18 @@ import XCTest final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDelegate { var manager: PolylineAnnotationManager! - var style: MockStyle! - var id = UUID().uuidString + var harness: AnnotationManagerTestingHarness! var annotations = [PolylineAnnotation]() var expectation: XCTestExpectation? var delegateAnnotations: [Annotation]? - var offsetCalculator: OffsetLineStringCalculator! - var mapboxMap: MockMapboxMap! - @TestSignal var displayLink: Signal override func setUp() { super.setUp() - style = MockStyle() - mapboxMap = MockMapboxMap() - offsetCalculator = OffsetLineStringCalculator(mapboxMap: mapboxMap) + harness = AnnotationManagerTestingHarness() manager = PolylineAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) + params: harness.makeParams(), + deps: harness.makeDeps()) for _ in 0...10 { let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] @@ -35,214 +25,11 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel } override func tearDown() { - style = nil - expectation = nil - delegateAnnotations = nil - mapboxMap = nil - offsetCalculator = nil + harness = nil manager = nil - super.tearDown() } - func testSourceSetup() { - style.addSourceStub.reset() - - _ = PolylineAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.type, SourceType.geoJson) - XCTAssertEqual(style.addSourceStub.invocations.last?.parameters.source.id, manager.id) - } - - func testAddLayer() throws { - style.addSourceStub.reset() - let initializedManager = PolylineAnnotationManager( - id: id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerWithPropertiesStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.type, LayerType.line) - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layer.id, initializedManager.id) - let addedLayer = try XCTUnwrap(style.addPersistentLayerStub.invocations.last?.parameters.layer as? LineLayer) - XCTAssertEqual(addedLayer.source, initializedManager.sourceId) - XCTAssertNil(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition) - } - - func testAddManagerWithDuplicateId() { - var annotations2 = [PolylineAnnotation]() - for _ in 0...50 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - let annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotations2.append(annotation) - } - - manager.annotations = annotations - let manager2 = PolylineAnnotationManager( - id: manager.id, - style: style, - layerPosition: nil, - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - manager2.annotations = annotations2 - - XCTAssertEqual(manager.annotations.count, 11) - XCTAssertEqual(manager2.annotations.count, 51) - } - - func testLayerPositionPassedCorrectly() { - let manager3 = PolylineAnnotationManager( - id: id, - style: style, - layerPosition: LayerPosition.at(4), - displayLink: displayLink, - offsetCalculator: offsetCalculator - ) - manager3.annotations = annotations - - XCTAssertEqual(style.addPersistentLayerStub.invocations.last?.parameters.layerPosition, LayerPosition.at(4)) - } - - func testDestroy() { - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testDestroyManagerWithDraggedAnnotations() { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.isDraggable = true - manager.annotations = [annotation] - // adds drag source/layer - _ = manager.handleDragBegin(with: annotation.id, context: .zero) - - manager.destroy() - - XCTAssertEqual(style.removeLayerStub.invocations.map(\.parameters), [id, id + "_drag"]) - XCTAssertEqual(style.removeSourceStub.invocations.map(\.parameters), [id, id + "_drag"]) - - style.removeLayerStub.reset() - style.removeSourceStub.reset() - - manager.destroy() - XCTAssertTrue(style.removeLayerStub.invocations.isEmpty) - XCTAssertTrue(style.removeSourceStub.invocations.isEmpty) - } - - func testSyncSourceAndLayer() { - manager.annotations = annotations - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - } - - func testDoNotSyncSourceAndLayerWhenNotNeeded() { - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 0) - } - - func testFeatureCollectionPassedtoGeoJSON() throws { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - let annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - let expectedFeatures = annotations.map(\.feature) - - manager.annotations = annotations - $displayLink.send() - - var invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, expectedFeatures) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - - do { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - let annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotations.append(annotation) - - manager.annotations = annotations - $displayLink.send() - - invocation = try XCTUnwrap(style.addGeoJSONSourceFeaturesStub.invocations.last) - XCTAssertEqual(invocation.parameters.features, [annotation].map(\.feature)) - XCTAssertEqual(invocation.parameters.sourceId, manager.id) - } - } - - @available(*, deprecated) - func testHandleTap() throws { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - let annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotations.append(annotation) - } - var taps = [MapContentGestureContext]() - annotations[0].tapHandler = { context in - taps.append(context) - return true - } - annotations[1].tapHandler = { _ in - return false // skips handling - } - manager.delegate = self - - manager.annotations = annotations - - // first annotation, handles tap - let context = MapContentGestureContext(point: .init(x: 1, y: 2), coordinate: .init(latitude: 3, longitude: 4)) - var handled = manager.handleTap(layerId: "layerId", feature: annotations[0].feature, context: context) - - var result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[0].id) - XCTAssertEqual(handled, true) - - XCTAssertEqual(taps.count, 1) - XCTAssertEqual(taps.first?.point, context.point) - XCTAssertEqual(taps.first?.coordinate, context.coordinate) - - // second annotation, skips handling tap - delegateAnnotations = nil - handled = manager.handleTap(layerId: "layerId", feature: annotations[1].feature, context: context) - - result = try XCTUnwrap(delegateAnnotations) - XCTAssertEqual(result[0].id, annotations[1].id) - XCTAssertEqual(handled, false) - - // invalid id - delegateAnnotations = nil - let invalidFeature = Feature(geometry: nil) - handled = manager.handleTap(layerId: "layerId", feature: invalidFeature, context: context) - - XCTAssertNil(delegateAnnotations) - XCTAssertEqual(handled, false) - XCTAssertEqual(taps.count, 1) - } - func testInitialLineCap() { let initialValue = manager.lineCap XCTAssertNil(initialValue) @@ -252,72 +39,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = LineCap.testConstantValue() manager.lineCap = value XCTAssertEqual(manager.lineCap, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-cap"] as! String, value.rawValue) - } - - func testLineCapAnnotationPropertiesAddedWithoutDuplicate() { - let newLineCapProperty = LineCap.testConstantValue() - let secondLineCapProperty = LineCap.testConstantValue() - - manager.lineCap = newLineCapProperty - $displayLink.send() - manager.lineCap = secondLineCapProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-cap"] as! String, secondLineCapProperty.rawValue) - } - - func testNewLineCapPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineCapProperty = LineCap.testConstantValue() - - manager.annotations = annotations - manager.lineCap = newLineCapProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-cap"]) + XCTAssertEqual(manager.impl.layerProperties["line-cap"] as! String, value.rawValue) } func testSetToNilLineCap() { let newLineCapProperty = LineCap.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-cap").value as! String manager.lineCap = newLineCapProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-cap"]) + XCTAssertNotNil(manager.impl.layerProperties["line-cap"]) + harness.triggerDisplayLink() manager.lineCap = nil - $displayLink.send() XCTAssertNil(manager.lineCap) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-cap"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-cap"] as! String, defaultValue) } - func testInitialLineMiterLimit() { let initialValue = manager.lineMiterLimit XCTAssertNil(initialValue) @@ -327,72 +64,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = 0.0 manager.lineMiterLimit = value XCTAssertEqual(manager.lineMiterLimit, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-miter-limit"] as! Double, value) - } - - func testLineMiterLimitAnnotationPropertiesAddedWithoutDuplicate() { - let newLineMiterLimitProperty = 0.0 - let secondLineMiterLimitProperty = 0.0 - - manager.lineMiterLimit = newLineMiterLimitProperty - $displayLink.send() - manager.lineMiterLimit = secondLineMiterLimitProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-miter-limit"] as! Double, secondLineMiterLimitProperty) - } - - func testNewLineMiterLimitPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineMiterLimitProperty = 0.0 - - manager.annotations = annotations - manager.lineMiterLimit = newLineMiterLimitProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-miter-limit"]) + XCTAssertEqual(manager.impl.layerProperties["line-miter-limit"] as! Double, value) } func testSetToNilLineMiterLimit() { let newLineMiterLimitProperty = 0.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-miter-limit").value as! Double manager.lineMiterLimit = newLineMiterLimitProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-miter-limit"]) + XCTAssertNotNil(manager.impl.layerProperties["line-miter-limit"]) + harness.triggerDisplayLink() manager.lineMiterLimit = nil - $displayLink.send() XCTAssertNil(manager.lineMiterLimit) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-miter-limit"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-miter-limit"] as! Double, defaultValue) } - func testInitialLineRoundLimit() { let initialValue = manager.lineRoundLimit XCTAssertNil(initialValue) @@ -402,72 +89,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = 0.0 manager.lineRoundLimit = value XCTAssertEqual(manager.lineRoundLimit, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-round-limit"] as! Double, value) - } - - func testLineRoundLimitAnnotationPropertiesAddedWithoutDuplicate() { - let newLineRoundLimitProperty = 0.0 - let secondLineRoundLimitProperty = 0.0 - - manager.lineRoundLimit = newLineRoundLimitProperty - $displayLink.send() - manager.lineRoundLimit = secondLineRoundLimitProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-round-limit"] as! Double, secondLineRoundLimitProperty) - } - - func testNewLineRoundLimitPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineRoundLimitProperty = 0.0 - - manager.annotations = annotations - manager.lineRoundLimit = newLineRoundLimitProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-round-limit"]) + XCTAssertEqual(manager.impl.layerProperties["line-round-limit"] as! Double, value) } func testSetToNilLineRoundLimit() { let newLineRoundLimitProperty = 0.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-round-limit").value as! Double manager.lineRoundLimit = newLineRoundLimitProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-round-limit"]) + XCTAssertNotNil(manager.impl.layerProperties["line-round-limit"]) + harness.triggerDisplayLink() manager.lineRoundLimit = nil - $displayLink.send() XCTAssertNil(manager.lineRoundLimit) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-round-limit"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-round-limit"] as! Double, defaultValue) } - func testInitialLineDasharray() { let initialValue = manager.lineDasharray XCTAssertNil(initialValue) @@ -477,72 +114,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = Array.random(withLength: .random(in: 0...10), generator: { 0.0 }) manager.lineDasharray = value XCTAssertEqual(manager.lineDasharray, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-dasharray"] as! [Double], value) - } - - func testLineDasharrayAnnotationPropertiesAddedWithoutDuplicate() { - let newLineDasharrayProperty = Array.random(withLength: .random(in: 0...10), generator: { 0.0 }) - let secondLineDasharrayProperty = Array.random(withLength: .random(in: 0...10), generator: { 0.0 }) - - manager.lineDasharray = newLineDasharrayProperty - $displayLink.send() - manager.lineDasharray = secondLineDasharrayProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-dasharray"] as! [Double], secondLineDasharrayProperty) - } - - func testNewLineDasharrayPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineDasharrayProperty = Array.random(withLength: .random(in: 0...10), generator: { 0.0 }) - - manager.annotations = annotations - manager.lineDasharray = newLineDasharrayProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-dasharray"]) + XCTAssertEqual(manager.impl.layerProperties["line-dasharray"] as! [Double], value) } func testSetToNilLineDasharray() { let newLineDasharrayProperty = Array.random(withLength: .random(in: 0...10), generator: { 0.0 }) let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-dasharray").value as! [Double] manager.lineDasharray = newLineDasharrayProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-dasharray"]) + XCTAssertNotNil(manager.impl.layerProperties["line-dasharray"]) + harness.triggerDisplayLink() manager.lineDasharray = nil - $displayLink.send() XCTAssertNil(manager.lineDasharray) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-dasharray"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-dasharray"] as! [Double], defaultValue) } - func testInitialLineDepthOcclusionFactor() { let initialValue = manager.lineDepthOcclusionFactor XCTAssertNil(initialValue) @@ -552,72 +139,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = 0.5 manager.lineDepthOcclusionFactor = value XCTAssertEqual(manager.lineDepthOcclusionFactor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-depth-occlusion-factor"] as! Double, value) - } - - func testLineDepthOcclusionFactorAnnotationPropertiesAddedWithoutDuplicate() { - let newLineDepthOcclusionFactorProperty = 0.5 - let secondLineDepthOcclusionFactorProperty = 0.5 - - manager.lineDepthOcclusionFactor = newLineDepthOcclusionFactorProperty - $displayLink.send() - manager.lineDepthOcclusionFactor = secondLineDepthOcclusionFactorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-depth-occlusion-factor"] as! Double, secondLineDepthOcclusionFactorProperty) - } - - func testNewLineDepthOcclusionFactorPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineDepthOcclusionFactorProperty = 0.5 - - manager.annotations = annotations - manager.lineDepthOcclusionFactor = newLineDepthOcclusionFactorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-depth-occlusion-factor"]) + XCTAssertEqual(manager.impl.layerProperties["line-depth-occlusion-factor"] as! Double, value) } func testSetToNilLineDepthOcclusionFactor() { let newLineDepthOcclusionFactorProperty = 0.5 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-depth-occlusion-factor").value as! Double manager.lineDepthOcclusionFactor = newLineDepthOcclusionFactorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-depth-occlusion-factor"]) + XCTAssertNotNil(manager.impl.layerProperties["line-depth-occlusion-factor"]) + harness.triggerDisplayLink() manager.lineDepthOcclusionFactor = nil - $displayLink.send() XCTAssertNil(manager.lineDepthOcclusionFactor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-depth-occlusion-factor"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-depth-occlusion-factor"] as! Double, defaultValue) } - func testInitialLineEmissiveStrength() { let initialValue = manager.lineEmissiveStrength XCTAssertNil(initialValue) @@ -627,72 +164,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = 50000.0 manager.lineEmissiveStrength = value XCTAssertEqual(manager.lineEmissiveStrength, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-emissive-strength"] as! Double, value) - } - - func testLineEmissiveStrengthAnnotationPropertiesAddedWithoutDuplicate() { - let newLineEmissiveStrengthProperty = 50000.0 - let secondLineEmissiveStrengthProperty = 50000.0 - - manager.lineEmissiveStrength = newLineEmissiveStrengthProperty - $displayLink.send() - manager.lineEmissiveStrength = secondLineEmissiveStrengthProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-emissive-strength"] as! Double, secondLineEmissiveStrengthProperty) - } - - func testNewLineEmissiveStrengthPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineEmissiveStrengthProperty = 50000.0 - - manager.annotations = annotations - manager.lineEmissiveStrength = newLineEmissiveStrengthProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-emissive-strength"]) + XCTAssertEqual(manager.impl.layerProperties["line-emissive-strength"] as! Double, value) } func testSetToNilLineEmissiveStrength() { let newLineEmissiveStrengthProperty = 50000.0 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-emissive-strength").value as! Double manager.lineEmissiveStrength = newLineEmissiveStrengthProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-emissive-strength"]) + XCTAssertNotNil(manager.impl.layerProperties["line-emissive-strength"]) + harness.triggerDisplayLink() manager.lineEmissiveStrength = nil - $displayLink.send() XCTAssertNil(manager.lineEmissiveStrength) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-emissive-strength"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-emissive-strength"] as! Double, defaultValue) } - func testInitialLineOcclusionOpacity() { let initialValue = manager.lineOcclusionOpacity XCTAssertNil(initialValue) @@ -702,72 +189,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = 0.5 manager.lineOcclusionOpacity = value XCTAssertEqual(manager.lineOcclusionOpacity, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-occlusion-opacity"] as! Double, value) - } - - func testLineOcclusionOpacityAnnotationPropertiesAddedWithoutDuplicate() { - let newLineOcclusionOpacityProperty = 0.5 - let secondLineOcclusionOpacityProperty = 0.5 - - manager.lineOcclusionOpacity = newLineOcclusionOpacityProperty - $displayLink.send() - manager.lineOcclusionOpacity = secondLineOcclusionOpacityProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-occlusion-opacity"] as! Double, secondLineOcclusionOpacityProperty) - } - - func testNewLineOcclusionOpacityPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineOcclusionOpacityProperty = 0.5 - - manager.annotations = annotations - manager.lineOcclusionOpacity = newLineOcclusionOpacityProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-occlusion-opacity"]) + XCTAssertEqual(manager.impl.layerProperties["line-occlusion-opacity"] as! Double, value) } func testSetToNilLineOcclusionOpacity() { let newLineOcclusionOpacityProperty = 0.5 let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-occlusion-opacity").value as! Double manager.lineOcclusionOpacity = newLineOcclusionOpacityProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-occlusion-opacity"]) + XCTAssertNotNil(manager.impl.layerProperties["line-occlusion-opacity"]) + harness.triggerDisplayLink() manager.lineOcclusionOpacity = nil - $displayLink.send() XCTAssertNil(manager.lineOcclusionOpacity) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-occlusion-opacity"] as! Double, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-occlusion-opacity"] as! Double, defaultValue) } - func testInitialLineTranslate() { let initialValue = manager.lineTranslate XCTAssertNil(initialValue) @@ -777,72 +214,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = [0.0, 0.0] manager.lineTranslate = value XCTAssertEqual(manager.lineTranslate, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate"] as! [Double], value) - } - - func testLineTranslateAnnotationPropertiesAddedWithoutDuplicate() { - let newLineTranslateProperty = [0.0, 0.0] - let secondLineTranslateProperty = [0.0, 0.0] - - manager.lineTranslate = newLineTranslateProperty - $displayLink.send() - manager.lineTranslate = secondLineTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate"] as! [Double], secondLineTranslateProperty) - } - - func testNewLineTranslatePropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineTranslateProperty = [0.0, 0.0] - - manager.annotations = annotations - manager.lineTranslate = newLineTranslateProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate"]) + XCTAssertEqual(manager.impl.layerProperties["line-translate"] as! [Double], value) } func testSetToNilLineTranslate() { let newLineTranslateProperty = [0.0, 0.0] let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-translate").value as! [Double] manager.lineTranslate = newLineTranslateProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate"]) + XCTAssertNotNil(manager.impl.layerProperties["line-translate"]) + harness.triggerDisplayLink() manager.lineTranslate = nil - $displayLink.send() XCTAssertNil(manager.lineTranslate) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate"] as! [Double], defaultValue) } - func testInitialLineTranslateAnchor() { let initialValue = manager.lineTranslateAnchor XCTAssertNil(initialValue) @@ -852,72 +239,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = LineTranslateAnchor.testConstantValue() manager.lineTranslateAnchor = value XCTAssertEqual(manager.lineTranslateAnchor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate-anchor"] as! String, value.rawValue) - } - - func testLineTranslateAnchorAnnotationPropertiesAddedWithoutDuplicate() { - let newLineTranslateAnchorProperty = LineTranslateAnchor.testConstantValue() - let secondLineTranslateAnchorProperty = LineTranslateAnchor.testConstantValue() - - manager.lineTranslateAnchor = newLineTranslateAnchorProperty - $displayLink.send() - manager.lineTranslateAnchor = secondLineTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate-anchor"] as! String, secondLineTranslateAnchorProperty.rawValue) - } - - func testNewLineTranslateAnchorPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineTranslateAnchorProperty = LineTranslateAnchor.testConstantValue() - - manager.annotations = annotations - manager.lineTranslateAnchor = newLineTranslateAnchorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate-anchor"]) + XCTAssertEqual(manager.impl.layerProperties["line-translate-anchor"] as! String, value.rawValue) } func testSetToNilLineTranslateAnchor() { let newLineTranslateAnchorProperty = LineTranslateAnchor.testConstantValue() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-translate-anchor").value as! String manager.lineTranslateAnchor = newLineTranslateAnchorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate-anchor"]) + XCTAssertNotNil(manager.impl.layerProperties["line-translate-anchor"]) + harness.triggerDisplayLink() manager.lineTranslateAnchor = nil - $displayLink.send() XCTAssertNil(manager.lineTranslateAnchor) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate-anchor"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-translate-anchor"] as! String, defaultValue) } - func testInitialLineTrimColor() { let initialValue = manager.lineTrimColor XCTAssertNil(initialValue) @@ -927,73 +264,23 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) manager.lineTrimColor = value XCTAssertEqual(manager.lineTrimColor, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-color"] as? String, value?.rawValue) - } - - func testLineTrimColorAnnotationPropertiesAddedWithoutDuplicate() { - let newLineTrimColorProperty = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - let secondLineTrimColorProperty = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - - manager.lineTrimColor = newLineTrimColorProperty - $displayLink.send() - manager.lineTrimColor = secondLineTrimColorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(StyleColor(rawValue: style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-color"] as! String), secondLineTrimColorProperty) - } - - func testNewLineTrimColorPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineTrimColorProperty = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - - manager.annotations = annotations - manager.lineTrimColor = newLineTrimColorProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-color"]) + XCTAssertEqual(manager.impl.layerProperties["line-trim-color"] as? String, value?.rawValue) } func testSetToNilLineTrimColor() { let newLineTrimColorProperty = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) let defaultValue = try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: StyleManager.layerPropertyDefaultValue(for: .line, property: "line-trim-color").value as! [Any], options: [])) manager.lineTrimColor = newLineTrimColorProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-color"]) + XCTAssertNotNil(manager.impl.layerProperties["line-trim-color"]) + harness.triggerDisplayLink() manager.lineTrimColor = nil - $displayLink.send() XCTAssertNil(manager.lineTrimColor) + harness.triggerDisplayLink() - let currentValue = try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-color"] as! [Any])) + let currentValue = try! JSONDecoder().decode(StyleColor.self, from: JSONSerialization.data(withJSONObject: harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-color"] as! [Any])) XCTAssertEqual(currentValue, defaultValue) } - func testInitialLineTrimFadeRange() { let initialValue = manager.lineTrimFadeRange XCTAssertNil(initialValue) @@ -1003,72 +290,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = [0.5, 0.5] manager.lineTrimFadeRange = value XCTAssertEqual(manager.lineTrimFadeRange, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-fade-range"] as! [Double], value) - } - - func testLineTrimFadeRangeAnnotationPropertiesAddedWithoutDuplicate() { - let newLineTrimFadeRangeProperty = [0.5, 0.5] - let secondLineTrimFadeRangeProperty = [0.5, 0.5] - - manager.lineTrimFadeRange = newLineTrimFadeRangeProperty - $displayLink.send() - manager.lineTrimFadeRange = secondLineTrimFadeRangeProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-fade-range"] as! [Double], secondLineTrimFadeRangeProperty) - } - - func testNewLineTrimFadeRangePropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineTrimFadeRangeProperty = [0.5, 0.5] - - manager.annotations = annotations - manager.lineTrimFadeRange = newLineTrimFadeRangeProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-fade-range"]) + XCTAssertEqual(manager.impl.layerProperties["line-trim-fade-range"] as! [Double], value) } func testSetToNilLineTrimFadeRange() { let newLineTrimFadeRangeProperty = [0.5, 0.5] let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-trim-fade-range").value as! [Double] manager.lineTrimFadeRange = newLineTrimFadeRangeProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-fade-range"]) + XCTAssertNotNil(manager.impl.layerProperties["line-trim-fade-range"]) + harness.triggerDisplayLink() manager.lineTrimFadeRange = nil - $displayLink.send() XCTAssertNil(manager.lineTrimFadeRange) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-fade-range"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-fade-range"] as! [Double], defaultValue) } - func testInitialLineTrimOffset() { let initialValue = manager.lineTrimOffset XCTAssertNil(initialValue) @@ -1078,72 +315,22 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = [0.5, 0.5].sorted() manager.lineTrimOffset = value XCTAssertEqual(manager.lineTrimOffset, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-offset"] as! [Double], value) - } - - func testLineTrimOffsetAnnotationPropertiesAddedWithoutDuplicate() { - let newLineTrimOffsetProperty = [0.5, 0.5].sorted() - let secondLineTrimOffsetProperty = [0.5, 0.5].sorted() - - manager.lineTrimOffset = newLineTrimOffsetProperty - $displayLink.send() - manager.lineTrimOffset = secondLineTrimOffsetProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-offset"] as! [Double], secondLineTrimOffsetProperty) - } - - func testNewLineTrimOffsetPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newLineTrimOffsetProperty = [0.5, 0.5].sorted() - - manager.annotations = annotations - manager.lineTrimOffset = newLineTrimOffsetProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-offset"]) + XCTAssertEqual(manager.impl.layerProperties["line-trim-offset"] as! [Double], value) } func testSetToNilLineTrimOffset() { let newLineTrimOffsetProperty = [0.5, 0.5].sorted() let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "line-trim-offset").value as! [Double] manager.lineTrimOffset = newLineTrimOffsetProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-offset"]) + XCTAssertNotNil(manager.impl.layerProperties["line-trim-offset"]) + harness.triggerDisplayLink() manager.lineTrimOffset = nil - $displayLink.send() XCTAssertNil(manager.lineTrimOffset) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-offset"] as! [Double], defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["line-trim-offset"] as! [Double], defaultValue) } - func testInitialSlot() { let initialValue = manager.slot XCTAssertNil(initialValue) @@ -1153,70 +340,21 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel let value = UUID().uuidString manager.slot = value XCTAssertEqual(manager.slot, value) - - // test layer and source synced and properties added - $displayLink.send() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, value) - } - - func testSlotAnnotationPropertiesAddedWithoutDuplicate() { - let newSlotProperty = UUID().uuidString - let secondSlotProperty = UUID().uuidString - - manager.slot = newSlotProperty - $displayLink.send() - manager.slot = secondSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.layerId, manager.id) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 2) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, secondSlotProperty) - } - - func testNewSlotPropertyMergedWithAnnotationProperties() { - var annotations = [PolylineAnnotation]() - for _ in 0...5 { - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.lineJoin = LineJoin.testConstantValue() - annotation.lineSortKey = 0.0 - annotation.lineZOffset = 0.0 - annotation.lineBlur = 50000.0 - annotation.lineBorderColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineBorderWidth = 50000.0 - annotation.lineColor = StyleColor(red: 255, green: 0, blue: 255, alpha: 1) - annotation.lineGapWidth = 50000.0 - annotation.lineOffset = 0.0 - annotation.lineOpacity = 0.5 - annotation.linePattern = UUID().uuidString - annotation.lineWidth = 50000.0 - annotations.append(annotation) - } - let newSlotProperty = UUID().uuidString - - manager.annotations = annotations - manager.slot = newSlotProperty - $displayLink.send() - - XCTAssertEqual(style.setLayerPropertiesStub.invocations.count, 1) - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties.count, annotations[0].layerProperties.count+1) - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertEqual(manager.impl.layerProperties["slot"] as! String, value) } func testSetToNilSlot() { let newSlotProperty = UUID().uuidString let defaultValue = StyleManager.layerPropertyDefaultValue(for: .line, property: "slot").value as! String manager.slot = newSlotProperty - $displayLink.send() - XCTAssertNotNil(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"]) + XCTAssertNotNil(manager.impl.layerProperties["slot"]) + harness.triggerDisplayLink() manager.slot = nil - $displayLink.send() XCTAssertNil(manager.slot) + harness.triggerDisplayLink() - XCTAssertEqual(style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) + XCTAssertEqual(harness.style.setLayerPropertiesStub.invocations.last?.parameters.properties["slot"] as! String, defaultValue) } func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) { @@ -1225,218 +363,6 @@ final class PolylineAnnotationManagerTests: XCTestCase, AnnotationInteractionDel expectation = nil } - func testGetAnnotations() { - let annotations = Array.random(withLength: 10) { - PolylineAnnotation(lineCoordinates: [ CLLocationCoordinate2D(latitude: 0, longitude: 0), CLLocationCoordinate2D(latitude: 10, longitude: 10)], isSelected: false, isDraggable: true) - } - manager.annotations = annotations - - // Dragged annotation will be added to internal list of dragged annotations. - let annotationToDrag = annotations.randomElement()! - _ = manager.handleDragBegin(with: annotationToDrag.id, context: .zero) - XCTAssertTrue(manager.annotations.contains(where: { $0.id == annotationToDrag.id })) - } - - func testHandleDragBeginIsDraggableFalse() throws { - manager.annotations = [ - PolylineAnnotation(id: "polyline1", lineCoordinates: [ CLLocationCoordinate2D(latitude: 0, longitude: 0), CLLocationCoordinate2D(latitude: 10, longitude: 10)], isSelected: false, isDraggable: false) - ] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "polyline1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 0) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 0) - } - func testHandleDragBeginInvalidFeatureId() { - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - - _ = manager.handleDragBegin(with: "not-a-feature", context: .zero) - - XCTAssertTrue(style.addSourceStub.invocations.isEmpty) - XCTAssertTrue(style.addPersistentLayerStub.invocations.isEmpty) - } - - func testDrag() throws { - let annotation = PolylineAnnotation(id: "polyline1", lineCoordinates: [ CLLocationCoordinate2D(latitude: 0, longitude: 0), CLLocationCoordinate2D(latitude: 10, longitude: 10)], isSelected: false, isDraggable: true) - manager.annotations = [annotation] - - style.addSourceStub.reset() - style.addPersistentLayerStub.reset() - _ = manager.handleDragBegin(with: "polyline1", context: .zero) - - let addSourceParameters = try XCTUnwrap(style.addSourceStub.invocations.last).parameters - let addLayerParameters = try XCTUnwrap(style.addPersistentLayerStub.invocations.last).parameters - - let addedLayer = try XCTUnwrap(addLayerParameters.layer as? LineLayer) - XCTAssertEqual(addedLayer.source, addSourceParameters.source.id) - XCTAssertEqual(addLayerParameters.layerPosition, .above(manager.id)) - XCTAssertEqual(addedLayer.id, manager.id + "_drag") - - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 1) - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.last?.parameters.id, "\(manager.id)_drag") - - _ = manager.handleDragBegin(with: "polyline1", context: .zero) - - XCTAssertEqual(style.addSourceStub.invocations.count, 1) - XCTAssertEqual(style.addPersistentLayerStub.invocations.count, 1) - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 0, longitude: 0) - mapboxMap.cameraState.zoom = 1 - - manager.handleDragChange(with: .zero, context: .zero) - - $displayLink.send() - - let updateSourceParameters = try XCTUnwrap(style.updateGeoJSONSourceStub.invocations.last).parameters - XCTAssertTrue(updateSourceParameters.id == addSourceParameters.source.id) - if case .featureCollection(let collection) = updateSourceParameters.geojson { - XCTAssertTrue(collection.features.contains(where: { $0.identifier?.rawValue as? String == annotation.id })) - } else { - XCTFail("GeoJSONObject should be a feature collection") - } - } - - func testDragHandlers() throws { - struct GestureData { - var annotation: PolylineAnnotation - var context: MapContentGestureContext - } - - let lineCoordinates = [ CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10) ] - var annotation = PolylineAnnotation(lineString: .init(lineCoordinates), isSelected: false, isDraggable: false) - annotation.isDraggable = true - - let beginDragStub = Stub(defaultReturnValue: false) - let changeDragStub = Stub() - let endDragStub = Stub() - annotation.dragBeginHandler = { annotation, context in - beginDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragChangeHandler = { annotation, context in - changeDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - annotation.dragEndHandler = { annotation, context in - endDragStub.call(with: GestureData(annotation: annotation, context: context)) - } - manager.annotations = [annotation] - - mapboxMap.pointStub.defaultReturnValue = CGPoint(x: 0, y: 0) - mapboxMap.coordinateForPointStub.defaultReturnValue = .init(latitude: 23.5432356, longitude: -12.5326744) - mapboxMap.cameraState.zoom = 1 - - var context = MapContentGestureContext(point: CGPoint(x: 0, y: 1), coordinate: .init(latitude: 2, longitude: 3)) - - // test it twice to cover the case when annotation was already on drag layer. - for _ in 0...1 { - beginDragStub.reset() - changeDragStub.reset() - endDragStub.reset() - - // skipped gesture - beginDragStub.defaultReturnValue = false - var res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 1) - XCTAssertEqual(res, false) - var data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - manager.handleDragEnd(context: context) - XCTAssertEqual(changeDragStub.invocations.count, 0) - XCTAssertEqual(endDragStub.invocations.count, 0) - - // handled gesture - context.point.x += 1 - context.coordinate.latitude += 1 - beginDragStub.defaultReturnValue = true - res = manager.handleDragBegin(with: annotation.id, context: context) - XCTAssertEqual(beginDragStub.invocations.count, 2) - XCTAssertEqual(res, true) - data = try XCTUnwrap(beginDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragChange(with: CGPoint(x: 10, y: 20), context: context) - XCTAssertEqual(changeDragStub.invocations.count, 1) - data = try XCTUnwrap(changeDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - - context.point.x += 1 - context.coordinate.latitude += 1 - manager.handleDragEnd(context: context) - XCTAssertEqual(endDragStub.invocations.count, 1) - data = try XCTUnwrap(endDragStub.invocations.last).parameters - XCTAssertEqual(data.annotation.id, annotation.id) - XCTAssertEqual(data.context.point, context.point) - XCTAssertEqual(data.context.coordinate, context.coordinate) - } - } - - func testDoesNotUpdateDragSourceWhenNoDragged() { - let annotation = PolylineAnnotation(id: "polyline1", lineCoordinates: [ CLLocationCoordinate2D(latitude: 0, longitude: 0), CLLocationCoordinate2D(latitude: 10, longitude: 10)], isSelected: false, isDraggable: true) - manager.annotations = [annotation] - $displayLink.send() - XCTAssertEqual(style.updateGeoJSONSourceStub.invocations.count, 0) - } - - func testRemovingDuplicatedAnnotations() { - let lineCoordinates1 = [ CLLocationCoordinate2DMake(1, 1), CLLocationCoordinate2DMake(11, 11) ] - let annotation1 = PolylineAnnotation(id: "A", lineString: .init(lineCoordinates1), isSelected: false, isDraggable: false) - let lineCoordinates2 = [ CLLocationCoordinate2DMake(2, 2), CLLocationCoordinate2DMake(12, 12) ] - let annotation2 = PolylineAnnotation(id: "B", lineString: .init(lineCoordinates2), isSelected: false, isDraggable: false) - let lineCoordinates3 = [ CLLocationCoordinate2DMake(3, 3), CLLocationCoordinate2DMake(13, 13) ] - let annotation3 = PolylineAnnotation(id: "A", lineString: .init(lineCoordinates3), isSelected: false, isDraggable: false) - manager.annotations = [annotation1, annotation2, annotation3] - - XCTAssertEqual(manager.annotations, [ - annotation1, - annotation2 - ]) - } - - func testSetNewAnnotations() { - let lineCoordinates1 = [ CLLocationCoordinate2DMake(1, 1), CLLocationCoordinate2DMake(11, 11) ] - let annotation1 = PolylineAnnotation(id: "A", lineString: .init(lineCoordinates1), isSelected: false, isDraggable: false) - let lineCoordinates2 = [ CLLocationCoordinate2DMake(2, 2), CLLocationCoordinate2DMake(12, 12) ] - let annotation2 = PolylineAnnotation(id: "B", lineString: .init(lineCoordinates2), isSelected: false, isDraggable: false) - let lineCoordinates3 = [ CLLocationCoordinate2DMake(3, 3), CLLocationCoordinate2DMake(13, 13) ] - let annotation3 = PolylineAnnotation(id: "C", lineString: .init(lineCoordinates3), isSelected: false, isDraggable: false) - - manager.set(newAnnotations: [ - (1, annotation1), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (1, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["A", "B"]) - - manager.set(newAnnotations: [ - (3, annotation3), - (2, annotation2) - ]) - - XCTAssertEqual(manager.annotations.map(\.id), ["C", "B"]) - } } // End of generated file diff --git a/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManager.swift b/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManager.swift index 18d13ccf51f5..2823bbfab2c3 100644 --- a/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManager.swift +++ b/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManager.swift @@ -1,18 +1,12 @@ import XCTest @testable import MapboxMaps -internal final class MockAnnotationManager: AnnotationManagerInternal { +internal final class MockAnnotationManager: AnnotationManagerImplProtocol { @Stubbed var id: String = "" - @Stubbed var sourceId: String = "" - - @Stubbed var layerId: String = "" - @Stubbed var allLayerIds: [String] = [] - @Stubbed var slot: String? - let destroyStub = Stub() func destroy() { destroyStub() diff --git a/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManagerFactory.swift b/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManagerFactory.swift deleted file mode 100644 index 2e52b3c2fccb..000000000000 --- a/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationManagerFactory.swift +++ /dev/null @@ -1,59 +0,0 @@ -@testable import MapboxMaps - -internal final class MockAnnotationManagerFactory: AnnotationManagerFactoryProtocol { - struct MakePointAnnotationManagerParams { - var id: String - var layerPosition: LayerPosition? - var clusterOptions: ClusterOptions? - } - let makePointAnnotationManagerStub = Stub(defaultReturnValue: MockAnnotationManager()) - func makePointAnnotationManager( - id: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions?) -> AnnotationManagerInternal { - return makePointAnnotationManagerStub.call(with: MakePointAnnotationManagerParams( - id: id, - layerPosition: layerPosition, - clusterOptions: clusterOptions)) - } - - struct MakePolylineAnnotationManagerParams { - var id: String - var layerPosition: LayerPosition? - } - let makePolylineAnnotationManagerStub = Stub(defaultReturnValue: MockAnnotationManager()) - func makePolylineAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return makePolylineAnnotationManagerStub.call(with: MakePolylineAnnotationManagerParams( - id: id, - layerPosition: layerPosition)) - } - - struct MakeCircleAnnotationManagerParams { - var id: String - var layerPosition: LayerPosition? - } - let makeCircleAnnotationManagerStub = Stub(defaultReturnValue: MockAnnotationManager()) - func makeCircleAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return makeCircleAnnotationManagerStub.call(with: MakeCircleAnnotationManagerParams( - id: id, - layerPosition: layerPosition)) - } - - struct MakePolygonAnnotationManagerParams { - var id: String - var layerPosition: LayerPosition? - } - let makePolygonAnnotationManagerStub = Stub(defaultReturnValue: MockAnnotationManager()) - internal func makePolygonAnnotationManager( - id: String, - layerPosition: LayerPosition? - ) -> AnnotationManagerInternal { - return makePolygonAnnotationManagerStub.call(with: MakePolygonAnnotationManagerParams( - id: id, - layerPosition: layerPosition)) - } -} diff --git a/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationOrchestatorImpl.swift b/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationOrchestatorImpl.swift deleted file mode 100644 index 7b08ecc997ca..000000000000 --- a/Tests/MapboxMapsTests/Annotations/Mocks/MockAnnotationOrchestatorImpl.swift +++ /dev/null @@ -1,97 +0,0 @@ -import Foundation -@testable import MapboxMaps - -final class MockAnnotationOrchestatorImpl: AnnotationOrchestratorImplProtocol { - @Stubbed - var managersByLayerId: [String: AnnotationManagerInternal] = [:] - - @Stubbed - var annotationManagersById: [String: AnnotationManager] = [:] - - struct MakePointAnnotationManagerParams: Equatable { - var id: String - var layerPosition: LayerPosition? - var clusterOptions: ClusterOptions? - } - let makePointAnnotationManagerStub = Stub( - defaultReturnValue: PointAnnotationManager( - id: "test", - style: MockStyle(), - layerPosition: .default, - displayLink: Signal { _ in .empty }, - mapFeatureQueryable: MockMapFeatureQueryable(), - imagesManager: MockAnnotationImagesManager(), - offsetCalculator: .init(mapboxMap: MockMapboxMap()) - ) - ) - func makePointAnnotationManager( - id: String, - layerPosition: LayerPosition?, - clusterOptions: ClusterOptions?) -> AnnotationManagerInternal { - return makePointAnnotationManagerStub.call(with: MakePointAnnotationManagerParams( - id: id, - layerPosition: layerPosition, - clusterOptions: clusterOptions)) - } - - struct MakePolygonAnnotationManagerParams: Equatable { - var id: String - var layerPosition: LayerPosition? - } - let makePolygonAnnotationManagerStub = Stub( - defaultReturnValue: PolygonAnnotationManager( - id: "test", - style: MockStyle(), - layerPosition: .default, - displayLink: Signal { _ in .empty }, - offsetCalculator: .init(mapboxMap: MockMapboxMap()))) - func makePolygonAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return makePolygonAnnotationManagerStub.call(with: MakePolygonAnnotationManagerParams( - id: id, - layerPosition: layerPosition)) - } - - struct MakePolylineAnnotationManagerParams: Equatable { - var id: String - var layerPosition: LayerPosition? - } - let makePolylineAnnotationManagerStub = Stub( - defaultReturnValue: PolylineAnnotationManager( - id: "test", - style: MockStyle(), - layerPosition: .default, - displayLink: Signal { _ in .empty }, - offsetCalculator: .init(mapboxMap: MockMapboxMap()))) - func makePolylineAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return makePolylineAnnotationManagerStub.call(with: MakePolylineAnnotationManagerParams( - id: id, - layerPosition: layerPosition)) - } - - struct MakeCircleAnnotationManagerParams: Equatable { - var id: String - var layerPosition: LayerPosition? - } - let makeCircleAnnotationManagerStub = Stub( - defaultReturnValue: CircleAnnotationManager( - id: "test", - style: MockStyle(), - layerPosition: .default, - displayLink: Signal { _ in .empty }, - offsetCalculator: .init(mapboxMap: MockMapboxMap()))) - func makeCircleAnnotationManager( - id: String, - layerPosition: LayerPosition?) -> AnnotationManagerInternal { - return makeCircleAnnotationManagerStub.call(with: MakeCircleAnnotationManagerParams( - id: id, - layerPosition: layerPosition)) - } - - let removeAnnotationManagerStub = Stub() - func removeAnnotationManager(withId id: String) { - removeAnnotationManagerStub.call(with: id)} -} diff --git a/Tests/MapboxMapsTests/Foundation/Mocks/MockMapViewDependencyProvider.swift b/Tests/MapboxMapsTests/Foundation/Mocks/MockMapViewDependencyProvider.swift index 6127fa225d30..04a6f1056049 100644 --- a/Tests/MapboxMapsTests/Foundation/Mocks/MockMapViewDependencyProvider.swift +++ b/Tests/MapboxMapsTests/Foundation/Mocks/MockMapViewDependencyProvider.swift @@ -55,7 +55,7 @@ final class MockMapViewDependencyProvider: MapViewDependencyProviderProtocol { view: UIView, mapboxMap: MapboxMapProtocol, mapFeatureQueryable: MapFeatureQueryable, - annotations: AnnotationOrchestratorImplProtocol, + annotationManagersByLayerId: Ref<[String: AnnotationManagerImplProtocol]>, cameraAnimationsManager: CameraAnimationsManagerProtocol) -> GestureManager { return GestureManager( panGestureHandler: MockPanGestureHandler( @@ -111,28 +111,6 @@ final class MockMapViewDependencyProvider: MapViewDependencyProviderProtocol { doubleTouchGestureRecognizer: doubleTouchGestureRecognizer)) } - // MARK: - Annotations - struct MakeAnnotationOrchestratorImplParams { - let view: UIView - let mapboxMap: MapboxMapProtocol - let mapFeatureQueryable: MapFeatureQueryable - let style: StyleProtocol - let displayLink: Signal - } - let makeAnnotationOrchestratorStub = Stub(defaultReturnValue: MockAnnotationOrchestatorImpl()) - func makeAnnotationOrchestratorImpl(in view: UIView, - mapboxMap: MapboxMapProtocol, - mapFeatureQueryable: MapFeatureQueryable, - style: StyleProtocol, - displayLink: Signal) -> AnnotationOrchestratorImplProtocol { - makeAnnotationOrchestratorStub.call(with: .init( - view: view, - mapboxMap: mapboxMap, - mapFeatureQueryable: mapFeatureQueryable, - style: style, - displayLink: displayLink)) - } - // MARK: - Events Manager let makeEventsManagerStub = Stub(defaultReturnValue: EventsManagerMock()) func makeEventsManager() -> EventsManagerProtocol { diff --git a/Tests/MapboxMapsTests/Gestures/MapContentGestureManagerTests.swift b/Tests/MapboxMapsTests/Gestures/MapContentGestureManagerTests.swift index ef50937b9399..25c71866f419 100644 --- a/Tests/MapboxMapsTests/Gestures/MapContentGestureManagerTests.swift +++ b/Tests/MapboxMapsTests/Gestures/MapContentGestureManagerTests.swift @@ -5,7 +5,6 @@ import XCTest class MapContentGestureManagerTests: XCTestCase { var me: MapContentGestureManager! - var annotations: MockAnnotationOrchestatorImpl! var mapboxMap: MockMapboxMap! var featureQueryable: MockMapFeatureQueryable! @TestSignal var onTap: Signal @@ -18,12 +17,13 @@ class MapContentGestureManagerTests: XCTestCase { var layerHandledTap = true var layerHandledLongPress = true + @MutableRef var annotationManagersByLayerId = [String: AnnotationManagerImplProtocol]() + override func setUp() { - annotations = MockAnnotationOrchestatorImpl() mapboxMap = MockMapboxMap() featureQueryable = MockMapFeatureQueryable() me = MapContentGestureManager( - annotations: annotations, + annotationManagersByLayerId: $annotationManagersByLayerId, mapboxMap: mapboxMap, mapFeatureQueryable: featureQueryable, onTap: onTap, @@ -49,7 +49,7 @@ class MapContentGestureManagerTests: XCTestCase { tokens.removeAll() mapTaps.removeAll() mapLongPresses.removeAll() - annotations = nil + annotationManagersByLayerId = [:] mapboxMap = nil featureQueryable = nil me = nil @@ -155,10 +155,9 @@ class MapContentGestureManagerTests: XCTestCase { func testAnnotationTap() throws { let manager = MockAnnotationManager() - let managersByLayerId = [ + annotationManagersByLayerId = [ "annotation-layer": manager ] - annotations.$managersByLayerId.getStub.defaultReturnValue = managersByLayerId manager.handleTapStub.defaultReturnValue = true // handles the tap @@ -195,10 +194,9 @@ class MapContentGestureManagerTests: XCTestCase { func testAnnotationLongPress() throws { let manager = MockAnnotationManager() - let managersByLayerId = [ + annotationManagersByLayerId = [ "annotation-layer": manager ] - annotations.$managersByLayerId.getStub.defaultReturnValue = managersByLayerId manager.handleLongPressStub.defaultReturnValue = true // handles the long-press @@ -235,10 +233,9 @@ class MapContentGestureManagerTests: XCTestCase { func testAnnotationDrag() throws { let manager = MockAnnotationManager() - let managersByLayerId = [ + annotationManagersByLayerId = [ "annotation-layer": manager ] - annotations.$managersByLayerId.getStub.defaultReturnValue = managersByLayerId manager.handleDragBeginStub.defaultReturnValue = true // handles the drag diff --git a/Tests/MapboxMapsTests/Style/DSL/MapStyleContentReconcilerTests.swift b/Tests/MapboxMapsTests/Style/DSL/MapStyleContentReconcilerTests.swift index 6e034a5ea983..6dc20d3105d4 100644 --- a/Tests/MapboxMapsTests/Style/DSL/MapStyleContentReconcilerTests.swift +++ b/Tests/MapboxMapsTests/Style/DSL/MapStyleContentReconcilerTests.swift @@ -6,21 +6,19 @@ final class MapContentReconcilerTests: XCTestCase { var me: MapContentReconciler! var styleManager: MockStyleManager! var sourceManager: MockStyleSourceManager! - var style: MockStyle! + var harness: AnnotationManagerTestingHarness! + var style: MockStyle { harness.style } var annotationsOrchestrator: AnnotationOrchestrator! - var orchestratorImpl: MockAnnotationOrchestatorImpl! var viewAnnotationsManager: ViewAnnotationManager! var locationManager: LocationManager! - var circleAnnotationManager: CircleAnnotationManager! @TestPublished var styleIsLoaded = true override func setUp() { styleManager = MockStyleManager() sourceManager = MockStyleSourceManager() - style = MockStyle() - orchestratorImpl = MockAnnotationOrchestatorImpl() - annotationsOrchestrator = AnnotationOrchestrator(impl: orchestratorImpl) + harness = AnnotationManagerTestingHarness() + annotationsOrchestrator = AnnotationOrchestrator(deps: harness.makeDeps()) viewAnnotationsManager = ViewAnnotationManager(containerView: UIView(), mapboxMap: MockMapboxMap(), displayLink: Signal(just: ())) locationManager = LocationManager( interfaceOrientationView: Ref({ nil }), @@ -28,13 +26,6 @@ final class MapContentReconcilerTests: XCTestCase { styleManager: style, mapboxMap: MockMapboxMap() ) - circleAnnotationManager = CircleAnnotationManager( - id: "test", - style: style, - layerPosition: .default, - displayLink: Signal { _ in .empty }, - offsetCalculator: OffsetPointCalculator(mapboxMap: MockMapboxMap()) - ) styleIsLoaded = true me = MapContentReconciler(styleManager: styleManager, sourceManager: sourceManager, styleIsLoaded: $styleIsLoaded) @@ -51,6 +42,10 @@ final class MapContentReconcilerTests: XCTestCase { me = nil sourceManager = nil styleManager = nil + harness = nil + annotationsOrchestrator = nil + + super.tearDown() } private func setContent(@MapContentBuilder content: () -> some MapContent) { @@ -565,7 +560,6 @@ final class MapContentReconcilerTests: XCTestCase { func testComponent() throws { sourceManager.sourceExistsStub.defaultReturnValue = true styleManager.styleLayerExistsStub.defaultReturnValue = true - orchestratorImpl.makeCircleAnnotationManagerStub.defaultReturnValue = circleAnnotationManager let route1 = MapContentFixture.Route(json: "foo") var component = MapContentFixture(id: "foo", route: route1, condition: true) @@ -577,14 +571,15 @@ final class MapContentReconcilerTests: XCTestCase { XCTAssertEqual(addedSource?.data, .string("foo")) XCTAssertEqual(viewAnnotationsManager.allAnnotations.count, 1) verifyAnnotationOptions(viewAnnotationsManager.allAnnotations.first, component.mapViewAnnotation) - XCTAssertEqual(circleAnnotationManager.annotations, [ + + let manager = try XCTUnwrap( annotationsOrchestrator.annotationManagersById["circle-test"] as? CircleAnnotationManager) + + XCTAssertEqual(manager.annotations, [ CircleAnnotation(id: "1", point: Point(LocationCoordinate2D(latitude: 10, longitude: 10))), CircleAnnotation(id: "2", point: Point(LocationCoordinate2D(latitude: 20, longitude: 20))) ]) - XCTAssertEqual(orchestratorImpl.removeAnnotationManagerStub.invocations.map(\.parameters), []) - XCTAssertEqual(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.map(\.parameters), [ - .init(id: "circle-test", layerPosition: .at(0)) - ]) + XCTAssertEqual(manager.impl.layerPosition, .at(0)) + XCTAssertEqual(locationManager.options, LocationOptions( puckType: .puck3D(Puck3DConfiguration(model: Model(), layerPosition: .above("circle-test"))), puckBearing: .heading, @@ -600,17 +595,14 @@ final class MapContentReconcilerTests: XCTestCase { XCTAssertEqual(styleManager.removeStyleLayerStub.invocations.last?.parameters, "condition-true") XCTAssertEqual(viewAnnotationsManager.allAnnotations.count, 1) verifyAnnotationOptions(viewAnnotationsManager.allAnnotations.first, component.mapViewAnnotation) - XCTAssertEqual(circleAnnotationManager.annotations, [ + + let manager2 = try XCTUnwrap( annotationsOrchestrator.annotationManagersById["circle-test"] as? CircleAnnotationManager) + XCTAssertIdentical(manager, manager2) + + XCTAssertEqual(manager2.annotations, [ CircleAnnotation(id: "1", point: Point(LocationCoordinate2D(latitude: 10, longitude: 10))), CircleAnnotation(id: "2", point: Point(LocationCoordinate2D(latitude: 20, longitude: 20))) ]) - XCTAssertEqual(orchestratorImpl.removeAnnotationManagerStub.invocations.map(\.parameters), [ - "circle-test" - ]) - XCTAssertEqual(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.map(\.parameters), [ - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)) - ]) XCTAssertEqual(locationManager.options, LocationOptions( puckType: .puck3D(Puck3DConfiguration(model: Model(), layerPosition: .above("circle-test"))), puckBearing: .heading, @@ -627,31 +619,13 @@ final class MapContentReconcilerTests: XCTestCase { XCTAssertEqual(sourceManager.updateGeoJSONSourceStub.invocations.count, 0) XCTAssertEqual(viewAnnotationsManager.allAnnotations.count, 1) verifyAnnotationOptions(viewAnnotationsManager.allAnnotations.first, component.mapViewAnnotation) - XCTAssertEqual(circleAnnotationManager.annotations, [ - CircleAnnotation(id: "1", point: Point(LocationCoordinate2D(latitude: 10, longitude: 10))), - CircleAnnotation(id: "2", point: Point(LocationCoordinate2D(latitude: 20, longitude: 20))) - ]) - XCTAssertEqual(orchestratorImpl.removeAnnotationManagerStub.invocations.map(\.parameters), [ - "circle-test", - "circle-test" - ]) - XCTAssertEqual(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.map(\.parameters), [ - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)) - ]) - XCTAssertEqual(locationManager.options, LocationOptions( - puckType: .puck3D(Puck3DConfiguration(model: Model(), layerPosition: .above("circle-test"))), - puckBearing: .heading, - puckBearingEnabled: false - )) let route2 = MapContentFixture.Route(json: "bar") style.styleRootLoaded.toggle() style.styleRootLoaded.toggle() component = MapContentFixture(id: "foo", route: route2, optional: "optional", condition: false) - setContent { component} + setContent { component } XCTAssertEqual(sourceManager.addSourceStub.invocations.count, 1) XCTAssertEqual(sourceManager.updateGeoJSONSourceStub.invocations.count, 1) @@ -663,21 +637,16 @@ final class MapContentReconcilerTests: XCTestCase { XCTAssertEqual(styleManager.removeStyleLayerStub.invocations.count, 1) XCTAssertEqual(viewAnnotationsManager.allAnnotations.count, 1) verifyAnnotationOptions(viewAnnotationsManager.allAnnotations.first, component.mapViewAnnotation) - XCTAssertEqual(circleAnnotationManager.annotations, [ - CircleAnnotation(id: "1", point: Point(LocationCoordinate2D(latitude: 10, longitude: 10))), - CircleAnnotation(id: "2", point: Point(LocationCoordinate2D(latitude: 20, longitude: 20))) - ]) - XCTAssertEqual(orchestratorImpl.removeAnnotationManagerStub.invocations.map(\.parameters), [ - "circle-test", - "circle-test", - "circle-test" - ]) - XCTAssertEqual(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.map(\.parameters), [ - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)) - ]) + + let manager3 = try XCTUnwrap( annotationsOrchestrator.annotationManagersById["circle-test"] as? CircleAnnotationManager) + XCTAssertIdentical(manager2, manager3) + + XCTAssertEqual(locationManager.options, LocationOptions( + puckType: .puck3D(Puck3DConfiguration(model: Model(), layerPosition: .above("circle-test"))), + puckBearing: .heading, + puckBearingEnabled: false + )) + XCTAssertEqual(locationManager.options, LocationOptions( puckType: .puck3D(Puck3DConfiguration(model: Model(), layerPosition: .above("circle-test"))), puckBearing: .heading, @@ -691,18 +660,8 @@ final class MapContentReconcilerTests: XCTestCase { XCTAssertEqual(sourceManager.removeSourceUncheckedStub.invocations.count, 1) XCTAssertEqual(sourceManager.removeSourceUncheckedStub.invocations.last?.parameters, "route") XCTAssertEqual(viewAnnotationsManager.allAnnotations.count, 0) - XCTAssertEqual(orchestratorImpl.removeAnnotationManagerStub.invocations.map(\.parameters), [ - "circle-test", - "circle-test", - "circle-test", - "circle-test" - ]) - XCTAssertEqual(orchestratorImpl.makeCircleAnnotationManagerStub.invocations.map(\.parameters), [ - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)), - .init(id: "circle-test", layerPosition: .at(0)) - ]) + + XCTAssertEqual(annotationsOrchestrator.annotationManagersById.count, 0) XCTAssertEqual(locationManager.options, LocationOptions()) }