diff options
Diffstat (limited to 'platform/darwin')
-rw-r--r-- | platform/darwin/scripts/update-examples.js | 152 | ||||
-rw-r--r-- | platform/darwin/src/MGLCircleStyleLayer.h | 17 | ||||
-rw-r--r-- | platform/darwin/src/MGLFillStyleLayer.h | 12 | ||||
-rw-r--r-- | platform/darwin/src/MGLLineStyleLayer.h | 17 | ||||
-rw-r--r-- | platform/darwin/src/MGLRasterSource.h | 15 | ||||
-rw-r--r-- | platform/darwin/src/MGLRasterStyleLayer.h | 10 | ||||
-rw-r--r-- | platform/darwin/src/MGLShapeSource.h | 14 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyleLayer.h.ejs | 7 | ||||
-rw-r--r-- | platform/darwin/src/MGLSymbolStyleLayer.h | 17 | ||||
-rw-r--r-- | platform/darwin/src/MGLVectorSource.h | 15 | ||||
-rw-r--r-- | platform/darwin/src/MGLVectorStyleLayer.h | 20 | ||||
-rw-r--r-- | platform/darwin/test/MGLDocumentationExampleTests.swift | 209 | ||||
-rw-r--r-- | platform/darwin/test/MGLStyleLayerTests.m | 8 | ||||
-rw-r--r-- | platform/darwin/test/MGLStyleTests.mm | 49 | ||||
-rw-r--r-- | platform/darwin/test/one-liner.json | 1 |
15 files changed, 521 insertions, 42 deletions
diff --git a/platform/darwin/scripts/update-examples.js b/platform/darwin/scripts/update-examples.js new file mode 100644 index 0000000000..2aeb80e139 --- /dev/null +++ b/platform/darwin/scripts/update-examples.js @@ -0,0 +1,152 @@ +'use strict'; + +const fs = require('fs'); +const execFileSync = require('child_process').execFileSync; +const _ = require('lodash'); + +const examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationExampleTests.swift', 'utf8'); + +// Regex extracts the following block +// /** Front matter to describe the example. **/ +// func testMGLClass$member() { +// ... +// //#-example-code +// let sampleCode: String? +// //#-end-example-code +// ... +// } +// +// into the following regex groups: +// 1 (test method name): "MGLClass" or "MGLClass$member" or "MGLClass$initWithArg_anotherArg_" +// 2 (indentation): " " +// 3 (sample code): "let sampleCode: String?" +const exampleRegex = /func test([\w$]+)\s*\(\)\s*\{[^]*?\n([ \t]+)\/\/#-example-code\n([^]+?)\n\2\/\/#-end-example-code\n/gm; + +/** + * Returns the given source with example code inserted into the documentation + * comment for the symbol at the given one-based line. + * + * @param {String} src Source code to insert the example code into. + * @param {Number} line One-based line number of the symbol being documented. + * @param {String} exampleCode Example code to insert. + * @returns {String} `src` with `exampleCode` inserted just above `line`. + */ +function completeSymbolInSource(src, line, exampleCode) { + // Split the file contents right before the symbol declaration (but after its documentation comment). + let srcUpToSymbol = src.split('\n', line - 1).join('\n'); + let srcFromSymbol = src.substr(srcUpToSymbol.length); + + // Match the documentation comment block that is not followed by the beginning or end of a declaration. + let commentMatch = srcUpToSymbol.match(/\/\*\*\s*(?:[^*]|\*(?!\/))+?\s*\*\/[^;{}]*?$/); + + // Replace the Swift code block with the test method’s contents. + let completedComment = commentMatch[0].replace(/^([ \t]*)```swift\n[^]*?```/m, function (m, indentation) { + // Apply the original indentation to each line. + return ('```swift\n' + exampleCode + '\n```').replace(/^/gm, indentation); + }); + + // Splice the modified comment into the overall file contents. + srcUpToSymbol = (srcUpToSymbol.substr(0, commentMatch.index) + completedComment + + srcUpToSymbol.substr(commentMatch.index + commentMatch[0].length)); + return srcUpToSymbol + srcFromSymbol; +} + +let examples = {}; +let match; +while ((match = exampleRegex.exec(examplesSrc)) !== null) { + let testMethodName = match[1], + indentation = match[2], + exampleCode = match[3]; + + // Trim leading whitespace from the example code. + exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), ''); + + examples[testMethodName] = exampleCode; +} + +function completeExamples(os) { + console.log(`Installing ${os} SDK examples…`); + + let sdk = os === 'iOS' ? 'iphonesimulator' : 'macosx'; + let sysroot = execFileSync('xcrun', ['--show-sdk-path', '--sdk', sdk]).toString().trim(); + let umbrellaPath = `platform/${os.toLowerCase()}/src/Mapbox.h`; + let docArgs = ['doc', '--objc', umbrellaPath, '--', + '-x', 'objective-c', '-I', 'platform/darwin/src/', '-isysroot', sysroot]; + let docStr = execFileSync('sourcekitten', docArgs).toString().trim(); + let docJson = JSON.parse(docStr); + _.forEach(docJson, function (result) { + _.forEach(result, function (structure, path) { + let src; + let newSrc; + // Recursively search for code blocks in documentation comments and populate + // them with example code from the test methods. Find and replace the code + // blocks in reverse to keep the SourceKitten line numbers accurate. + _.forEachRight(structure['key.substructure'], function completeSubstructure(substructure, idx, substructures, symbolPath) { + if (!symbolPath) { + symbolPath = [substructure['key.name']]; + } + _.forEachRight(substructure['key.substructure'], function (substructure, idx, substructures) { + completeSubstructure(substructure, idx, substructures, _.concat(symbolPath, substructure['key.name'])); + }); + + let comment = substructure['key.doc.comment']; + if (!comment || !comment.match(/^(?:\s*)```swift\n/m)) { + return; + } + + // Lazily read in the existing file. + if (!src) { + newSrc = src = fs.readFileSync(path, 'utf8'); + } + + // Get the contents of the test method whose name matches the symbol path. + let testMethodName = symbolPath.join('$').replace(/$[+-]/, '').replace(/:/g, '_'); + let example = examples[testMethodName]; + if (!example) { + console.error(`MGLDocumentationExampleTests.${testMethodName}() not found.`); + process.exit(1); + } + + // Resolve conditional compilation blocks. + example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\n/gm, + function (m, indentation, ifOs, ifCase, elseCase) { + return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), ''); + }); + + // Insert the test method contents into the documentation comment just + // above the substructure. + let startLine = substructure['key.parsed_scope.start']; + newSrc = completeSymbolInSource(newSrc, startLine, example); + }); + + if (!src) { + return; + } + + // Write out the modified file contents. + if (src === newSrc) { + console.log('Skipping', path); + } else { + console.log('Updating', path); + if (['0', 'false'].indexOf(process.env.DRY_RUN || '0') !== -1) { + fs.writeFileSync(path, newSrc); + } + } + }); + }); +} + +function ensureSourceKittenIsInstalled() { + try { + execFileSync('which', ['sourcekitten']); + } catch (e) { + console.log(`Installing SourceKitten via Homebrew…`); + execFileSync('brew', ['install', 'sourcekitten']); + } +} + +ensureSourceKittenIsInstalled(); + +// Where a particular comment is part of both SDKs, prefer the iOS example. +completeExamples('macOS'); +completeExamples('iOS'); diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h index b57e245da2..d2e043e22a 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.h +++ b/platform/darwin/src/MGLCircleStyleLayer.h @@ -59,8 +59,21 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslateAnchor) { otherwise, find it using the `MGLStyle.layers` property. You can also create a new circle style layer and add it to the style using a method such as `-[MGLStyle addLayer:]`. - - <!--EXAMPLE: MGLCircleStyleLayer--> + + ### Example + + ```swift + let layer = MGLCircleStyleLayer(identifier: "circles", source: population) + layer.sourceLayerIdentifier = "population" + layer.circleColor = MGLStyleValue(rawValue: .green) + layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [ + 12: MGLStyleValue(rawValue: 2), + 22: MGLStyleValue(rawValue: 180) + ]) + layer.circleOpacity = MGLStyleValue(rawValue: 0.7) + layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married") + mapView.style.addLayer(layer) + ``` */ @interface MGLCircleStyleLayer : MGLVectorStyleLayer diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h index 2638e85aa5..184f44ef65 100644 --- a/platform/darwin/src/MGLFillStyleLayer.h +++ b/platform/darwin/src/MGLFillStyleLayer.h @@ -37,8 +37,16 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) { otherwise, find it using the `MGLStyle.layers` property. You can also create a new fill style layer and add it to the style using a method such as `-[MGLStyle addLayer:]`. - - <!--EXAMPLE: MGLFillStyleLayer--> + + ### Example + + ```swift + let layer = MGLFillStyleLayer(identifier: "parks", source: parks) + layer.sourceLayerIdentifier = "parks" + layer.fillColor = MGLStyleValue(rawValue: .green) + layer.predicate = NSPredicate(format: "type == %@", "national-park") + mapView.style.addLayer(layer) + ``` */ @interface MGLFillStyleLayer : MGLVectorStyleLayer diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h index c3371aa2a7..f049ae1db1 100644 --- a/platform/darwin/src/MGLLineStyleLayer.h +++ b/platform/darwin/src/MGLLineStyleLayer.h @@ -87,8 +87,21 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslateAnchor) { otherwise, find it using the `MGLStyle.layers` property. You can also create a new line style layer and add it to the style using a method such as `-[MGLStyle addLayer:]`. - - <!--EXAMPLE: MGLLineStyleLayer--> + + ### Example + + ```swift + let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails) + layer.sourceLayerIdentifier = "trails" + layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [ + 14: MGLStyleValue(rawValue: 2), + 18: MGLStyleValue(rawValue: 20), + ]) + layer.lineColor = MGLStyleValue(rawValue: .brown) + layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round)) + layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking") + mapView.style.addLayer(layer) + ``` */ @interface MGLLineStyleLayer : MGLVectorStyleLayer diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h index 3efd84f383..cd95e85c5b 100644 --- a/platform/darwin/src/MGLRasterSource.h +++ b/platform/darwin/src/MGLRasterSource.h @@ -35,8 +35,19 @@ extern const MGLTileSourceOption MGLTileSourceOptionTileSize; `MGLRasterSource` object that you can use to initialize new style layers. You can also add and remove sources dynamically using methods such as `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`. - - <!--EXAMPLE: MGLRasterSource--> + + ### Example + + ```swift + let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .tileSize: 512, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style.addSource(source) ``` */ @interface MGLRasterSource : MGLTileSource diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h index 7b53eebf96..45ab25a8f1 100644 --- a/platform/darwin/src/MGLRasterStyleLayer.h +++ b/platform/darwin/src/MGLRasterStyleLayer.h @@ -23,8 +23,14 @@ NS_ASSUME_NONNULL_BEGIN otherwise, find it using the `MGLStyle.layers` property. You can also create a new raster style layer and add it to the style using a method such as `-[MGLStyle addLayer:]`. - - <!--EXAMPLE: MGLRasterStyleLayer--> + + ### Example + + ```swift + let layer = MGLRasterStyleLayer(identifier: "clouds", source: source) + layer.rasterOpacity = MGLStyleValue(rawValue: 0.5) + mapView.style.addLayer(layer) + ``` */ @interface MGLRasterStyleLayer : MGLForegroundStyleLayer diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h index 0eb454437b..30e299d2b1 100644 --- a/platform/darwin/src/MGLShapeSource.h +++ b/platform/darwin/src/MGLShapeSource.h @@ -74,8 +74,18 @@ extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance; Any vector style layer initialized with a shape source should have a `nil` value in its `sourceLayerIdentifier` property. - - <!--EXAMPLE: MGLShapeSource--> + + ### Example + + ```swift + var coordinates: [CLLocationCoordinate2D] = [ + CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42), + CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04), + ] + let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count)) + let shape = MGLShapeCollectionFeature(shapes: [polyline]) + let source = MGLShapeSource(identifier: "lines", shape: shape, options: nil) + mapView.style.addSource(source) ``` */ @interface MGLShapeSource : MGLSource diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs index ac95022ea7..17529b8f9d 100644 --- a/platform/darwin/src/MGLStyleLayer.h.ejs +++ b/platform/darwin/src/MGLStyleLayer.h.ejs @@ -67,8 +67,11 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) { otherwise, find it using the `MGLStyle.layers` property. You can also create a new <%- type %> style layer and add it to the style using a method such as `-[MGLStyle addLayer:]`. - - <!--EXAMPLE: MGL<%- camelize(type) %>StyleLayer--> + + ### Example + + ```swift + ``` */ <% } -%> @interface MGL<%- camelize(type) %>StyleLayer : MGL<%- diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index 052d67617a..ca34698159 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -260,8 +260,21 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { otherwise, find it using the `MGLStyle.layers` property. You can also create a new symbol style layer and add it to the style using a method such as `-[MGLStyle addLayer:]`. - - <!--EXAMPLE: MGLSymbolStyleLayer--> + + ### Example + + ```swift + let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois) + layer.sourceLayerIdentifier = "pois" + layer.iconImageName = MGLStyleValue(rawValue: "coffee") + layer.iconScale = MGLStyleValue(rawValue: 0.5) + layer.textField = MGLStyleValue(rawValue: "{name}") + layer.textTranslate = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0))) + layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left)) + layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left)) + layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee") + mapView.style.addLayer(layer) + ``` */ @interface MGLSymbolStyleLayer : MGLVectorStyleLayer diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h index ba8f075b5a..aa867adb6c 100644 --- a/platform/darwin/src/MGLVectorSource.h +++ b/platform/darwin/src/MGLVectorSource.h @@ -24,8 +24,19 @@ NS_ASSUME_NONNULL_BEGIN (<var>extent</var> × 2) − 1, inclusive. Any vector style layer initialized with a vector source must have a non-`nil` value in its `sourceLayerIdentifier` property. - - <!--EXAMPLE: MGLVectorSource--> + + ### Example + + ```swift + let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style.addSource(source) + ``` */ @interface MGLVectorSource : MGLTileSource diff --git a/platform/darwin/src/MGLVectorStyleLayer.h b/platform/darwin/src/MGLVectorStyleLayer.h index 50e56d8643..d33494c3e4 100644 --- a/platform/darwin/src/MGLVectorStyleLayer.h +++ b/platform/darwin/src/MGLVectorStyleLayer.h @@ -59,7 +59,10 @@ NS_ASSUME_NONNULL_BEGIN <li><code>NSContainsPredicateOperatorType</code> (<code>CONTAINS</code>)</li> </ul> - To test whether a feature has or lacks a specific attribute, compare the attribute to `NULL` or `NIL`. Predicates created using the `+[NSPredicate predicateWithValue:]` method are also supported. String operators and custom operators are not supported. + To test whether a feature has or lacks a specific attribute, compare the + attribute to `NULL` or `NIL`. Predicates created using the + `+[NSPredicate predicateWithValue:]` method are also supported. String + operators and custom operators are not supported. For details about the predicate format string syntax, consult the “Predicate Format String Syntax” chapter of the @@ -130,8 +133,19 @@ NS_ASSUME_NONNULL_BEGIN style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use `%K` in the format string to represent these variables: `@"%K == 'LineString'", @"$type"`. - - <!--EXAMPLE: MGLVectorStyleLayer.predicate--> + + ### Example + + To filter the layer to include only the features whose `index` attribute is 5 + or 10 and whose `ele` attribute is at least 1,500, you could create an + `NSCompoundPredicate` along these lines: + + ```swift + let layer = MGLLineStyleLayer(identifier: "contour", source: terrain) + layer.sourceLayerIdentifier = "contours" + layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0") + mapView.style.addLayer(layer) + ``` */ @property (nonatomic, nullable) NSPredicate *predicate; diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift new file mode 100644 index 0000000000..9243924328 --- /dev/null +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -0,0 +1,209 @@ +import XCTest +import Mapbox +#if os(iOS) + import UIKit +#else + import Cocoa +#endif + +/** + Test cases that ensure the inline examples in the project documentation + compile. + + To add an example: + 1. Add a test case named in the form testMGLClass or testMGLClass$method. + 2. Wrap the code you'd like to appear in the documentation within the + following comment blocks: + ``` + //#-example-code + ... + //#-end-example-code + ``` + 3. Insert an empty Swift code block inside the header file where you'd like the + example code to be inserted. + 4. Run `make darwin-update-examples` to extract example code from the test + method below and insert it into the header. + */ +class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { + var mapView: MGLMapView! + var styleLoadingExpectation: XCTestExpectation! + + override func setUp() { + super.setUp() + let styleURL = Bundle(for: MGLDocumentationExampleTests.self).url(forResource: "one-liner", withExtension: "json") + mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: 256, height: 256), styleURL: styleURL) + mapView.delegate = self + styleLoadingExpectation = expectation(description: "Map view should finish loading style") + waitForExpectations(timeout: 1, handler: nil) + } + + override func tearDown() { + mapView = nil + styleLoadingExpectation = nil + super.tearDown() + } + + func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) { + styleLoadingExpectation.fulfill() + } + + func testMGLShapeSource() { + //#-example-code + var coordinates: [CLLocationCoordinate2D] = [ + CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42), + CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04), + ] + let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count)) + let shape = MGLShapeCollectionFeature(shapes: [polyline]) + let source = MGLShapeSource(identifier: "lines", shape: shape, options: nil) + mapView.style.addSource(source) + //#-end-example-code + + XCTAssertNotNil(mapView.style.source(withIdentifier: "lines")) + } + + func testMGLRasterSource() { + //#-example-code + let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .tileSize: 512, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style.addSource(source) + //#-end-example-code + + XCTAssertNotNil(mapView.style.source(withIdentifier: "clouds")) + } + + func testMGLVectorSource() { + //#-example-code + let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style.addSource(source) + //#-end-example-code + + XCTAssertNotNil(mapView.style.source(withIdentifier: "pois")) + } + + func testMGLCircleStyleLayer() { + let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style.addSource(population) + + //#-example-code + let layer = MGLCircleStyleLayer(identifier: "circles", source: population) + layer.sourceLayerIdentifier = "population" + layer.circleColor = MGLStyleValue(rawValue: .green) + layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [ + 12: MGLStyleValue(rawValue: 2), + 22: MGLStyleValue(rawValue: 180) + ]) + layer.circleOpacity = MGLStyleValue(rawValue: 0.7) + layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married") + mapView.style.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style.layer(withIdentifier: "circles")) + } + + func testMGLLineStyleLayer() { + let trails = MGLVectorSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style.addSource(trails) + + //#-example-code + let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails) + layer.sourceLayerIdentifier = "trails" + layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [ + 14: MGLStyleValue(rawValue: 2), + 18: MGLStyleValue(rawValue: 20), + ]) + layer.lineColor = MGLStyleValue(rawValue: .brown) + layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round)) + layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking") + mapView.style.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style.layer(withIdentifier: "trails-path")) + } + + func testMGLFillStyleLayer() { + let parks = MGLVectorSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style.addSource(parks) + + //#-example-code + let layer = MGLFillStyleLayer(identifier: "parks", source: parks) + layer.sourceLayerIdentifier = "parks" + layer.fillColor = MGLStyleValue(rawValue: .green) + layer.predicate = NSPredicate(format: "type == %@", "national-park") + mapView.style.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style.layer(withIdentifier: "parks")) + } + + func testMGLSymbolStyleLayer() { + let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style.addSource(pois) + + //#-example-code + let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois) + layer.sourceLayerIdentifier = "pois" + layer.iconImageName = MGLStyleValue(rawValue: "coffee") + layer.iconScale = MGLStyleValue(rawValue: 0.5) + layer.textField = MGLStyleValue(rawValue: "{name}") + #if os(macOS) + var vector = CGVector(dx: 10, dy: 0) + layer.textTranslate = MGLStyleValue(rawValue: NSValue(bytes: &vector, objCType: "{CGVector=dd}")) + #else + layer.textTranslate = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0))) + #endif + layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left)) + layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left)) + layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee") + mapView.style.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style.layer(withIdentifier: "coffeeshops")) + } + + func testMGLRasterStyleLayer() { + let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [ + .minimumZoomLevel: 9, + .maximumZoomLevel: 16, + .tileSize: 512, + .attributionInfos: [ + MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com")) + ] + ]) + mapView.style.addSource(source) + + //#-example-code + let layer = MGLRasterStyleLayer(identifier: "clouds", source: source) + layer.rasterOpacity = MGLStyleValue(rawValue: 0.5) + mapView.style.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style.layer(withIdentifier: "clouds")) + } + + func testMGLVectorStyleLayer$predicate() { + let terrain = MGLVectorSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style.addSource(terrain) + + //#-example-code + let layer = MGLLineStyleLayer(identifier: "contour", source: terrain) + layer.sourceLayerIdentifier = "contours" + layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0") + mapView.style.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style.layer(withIdentifier: "contour")) + } +} diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m index 590d6eda7f..66bdc0df0b 100644 --- a/platform/darwin/test/MGLStyleLayerTests.m +++ b/platform/darwin/test/MGLStyleLayerTests.m @@ -10,6 +10,7 @@ - (void)setUp { [super setUp]; + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; #if TARGET_OS_IPHONE UIApplication *app = [UIApplication sharedApplication]; UIViewController *vc = [[UIViewController alloc] init]; @@ -19,12 +20,17 @@ [vc.view addSubview:_mapView]; _mapView.delegate = self; #else - [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; NSWindowController *windowController = [[NSWindowController alloc] initWithWindowNibName:@"MGLStyleLayerTests" owner:self]; [windowController showWindow:nil]; #endif } +- (void)tearDown { + _mapView = nil; + + [super tearDown]; +} + - (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean { NS_MUTABLE_ARRAY_OF(NSString *) *components = [name componentsSeparatedByString:@"-"].mutableCopy; if (isBoolean) { diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm index 55a5df08ca..bcad7ab508 100644 --- a/platform/darwin/test/MGLStyleTests.mm +++ b/platform/darwin/test/MGLStyleTests.mm @@ -1,3 +1,4 @@ +#import "MGLAccountManager.h" #import "MGLMapView.h" #import "MGLStyle_Private.h" #import "MGLOpenGLStyleLayer.h" @@ -36,9 +37,19 @@ - (void)setUp { [super setUp]; - + + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; - self.style = [[MGLStyle alloc] initWithMapView:self.mapView]; +} + +- (void)tearDown { + self.mapView = nil; + + [super tearDown]; +} + +- (MGLStyle *)style { + return self.mapView.style; } - (void)testUnversionedStyleURLs { @@ -174,18 +185,18 @@ - (void)testAddingLayersWithDuplicateIdentifiers { //Just some source MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]]; - [self.mapView.style addSource: source]; + [self.style addSource: source]; //Add initial layer MGLFillStyleLayer *initial = [[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]; - [self.mapView.style addLayer:initial]; + [self.style addLayer:initial]; //Try to add the duplicate - XCTAssertThrowsSpecificNamed([self.mapView.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); - XCTAssertThrowsSpecificNamed([self.mapView.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException"); } - (NSString *)stringWithContentsOfStyleHeader { @@ -209,8 +220,8 @@ #endif XCTAssertNotNil(image); - [self.mapView.style setImage:image forName:imageName]; - MGLImage *styleImage = [self.mapView.style imageForName:imageName]; + [self.style setImage:image forName:imageName]; + MGLImage *styleImage = [self.style imageForName:imageName]; XCTAssertNotNil(styleImage); XCTAssertEqual(image.size.width, styleImage.size.width); @@ -218,29 +229,27 @@ } - (void)testLayersOrder { - [self.mapView setStyleURL:[MGLStyle streetsStyleURLWithVersion:8]]; - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; NSURL *url = [NSURL fileURLWithPath:filePath]; MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; + [self.style addSource:source]; MGLCircleStyleLayer *layer1 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer1" source:source]; - [self.mapView.style addLayer:layer1]; + [self.style addLayer:layer1]; MGLCircleStyleLayer *layer3 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer3" source:source]; - [self.mapView.style addLayer:layer3]; + [self.style addLayer:layer3]; MGLCircleStyleLayer *layer2 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer2" source:source]; - [self.mapView.style insertLayer:layer2 aboveLayer:layer1]; + [self.style insertLayer:layer2 aboveLayer:layer1]; MGLCircleStyleLayer *layer4 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer4" source:source]; - [self.mapView.style insertLayer:layer4 aboveLayer:layer3]; + [self.style insertLayer:layer4 aboveLayer:layer3]; MGLCircleStyleLayer *layer0 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer0" source:source]; - [self.mapView.style insertLayer:layer0 belowLayer:layer1]; + [self.style insertLayer:layer0 belowLayer:layer1]; - NSArray<MGLStyleLayer *> *layers = [self.mapView.style layers]; + NSArray<MGLStyleLayer *> *layers = [self.style layers]; XCTAssert([[layers[0] identifier] isEqualToString:layer0.identifier]); XCTAssert([[layers[1] identifier] isEqualToString:layer1.identifier]); diff --git a/platform/darwin/test/one-liner.json b/platform/darwin/test/one-liner.json new file mode 100644 index 0000000000..23c546181f --- /dev/null +++ b/platform/darwin/test/one-liner.json @@ -0,0 +1 @@ +{"version":8,"sources":{},"layers":[]}
\ No newline at end of file |