From cfd8a517ce2a099c0cf229353f0d8b0685a3234f Mon Sep 17 00:00:00 2001 From: zmiao Date: Fri, 28 Feb 2020 16:19:38 +0200 Subject: [PATCH] update unit tests, fix point within polygon --- .../expression/definitions/within.js | 18 ++- src/style-spec/feature_filter/convert.js | 3 +- src/style-spec/feature_filter/index.js | 27 ++-- test/unit/style-spec/feature_filter.test.js | 151 ++++++++++-------- 4 files changed, 118 insertions(+), 81 deletions(-) diff --git a/src/style-spec/expression/definitions/within.js b/src/style-spec/expression/definitions/within.js index ede9cd82a0b..e6f790145af 100644 --- a/src/style-spec/expression/definitions/within.js +++ b/src/style-spec/expression/definitions/within.js @@ -71,6 +71,14 @@ function getLngLatPoints(line, canonical) { return coords; } +function onBoundary(p, p1, p2) { + const x1 = p[0] - p1[0]; + const y1 = p[1] - p1[1]; + const x2 = p[0] - p2[0]; + const y2 = p[1] - p2[1]; + return (x1 * y2 - x2 * y1 === 0) && (x1 * x2 <= 0) && (y1 * y2 <= 0); +} + function rayIntersect(p, p1, p2) { return ((p1[1] > p[1]) !== (p2[1] > p[1])) && (p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0]); } @@ -80,8 +88,9 @@ function pointWithinPolygon(point, rings) { let inside = false; for (let i = 0, len = rings.length; i < len; i++) { const ring = rings[i]; - for (let j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) { - if (rayIntersect(point, ring[j], ring[k])) inside = !inside; + for (let j = 0, len2 = ring.length; j < len2 - 1; j++) { + if (onBoundary(point, ring[j], ring[j + 1])) return false; + if (rayIntersect(point, ring[j], ring[j + 1])) inside = !inside; } } return inside; @@ -173,8 +182,9 @@ function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPo const lngLatPoints = []; for (const points of ctx.geometry()) { for (const point of points) { - lngLatPoints.push(getLngLatPoint(point, ctx.canonicalID())); - updateBBox(pointBBox, point); + const p = getLngLatPoint(point, ctx.canonicalID()); + lngLatPoints.push(p); + updateBBox(pointBBox, p); } } if (!boxWithinBox(pointBBox, polyBBox)) return false; diff --git a/src/style-spec/feature_filter/convert.js b/src/style-spec/feature_filter/convert.js index ed5100f947c..d7d473c2c4a 100644 --- a/src/style-spec/feature_filter/convert.js +++ b/src/style-spec/feature_filter/convert.js @@ -64,8 +64,7 @@ export default function convertFilter(filter: FilterSpecification): mixed { * produce a `false` result. */ function _convertFilter(filter: FilterSpecification, expectedTypes: ExpectedTypes): mixed { - const needGeo = false; - if (isExpressionFilter(filter, needGeo)) { return filter; } + if (isExpressionFilter(filter)) { return filter; } if (!filter) return true; const op = filter[0]; diff --git a/src/style-spec/feature_filter/index.js b/src/style-spec/feature_filter/index.js index f978b2af296..96aef4ccc59 100644 --- a/src/style-spec/feature_filter/index.js +++ b/src/style-spec/feature_filter/index.js @@ -5,17 +5,15 @@ import type {GlobalProperties, Feature} from '../expression'; import type {CanonicalTileID} from '../../source/tile_id'; type FilterExpression = (globalProperties: GlobalProperties, feature: Feature, canonical?: CanonicalTileID) => boolean; -export type FeatureFilter ={filter: FilterExpression, - needGeometry: boolean}; +export type FeatureFilter ={filter: FilterExpression, needGeometry: boolean}; export default createFilter; export {isExpressionFilter}; -function isExpressionFilter(filter: any, needGeometry: boolean) { +function isExpressionFilter(filter: any) { if (filter === true || filter === false) { return true; } - if (!Array.isArray(filter) || filter.length === 0) { return false; } @@ -41,14 +39,11 @@ function isExpressionFilter(filter: any, needGeometry: boolean) { case 'any': case 'all': for (const f of filter.slice(1)) { - if (!isExpressionFilter(f, needGeometry) && typeof f !== 'boolean') { + if (!isExpressionFilter(f) && typeof f !== 'boolean') { return false; } } return true; - case 'within': - needGeometry = true; - return true; default: return true; } @@ -79,8 +74,7 @@ function createFilter(filter: any): FeatureFilter { return {filter: () => true, needGeometry: false}; } - const withinExpr = false; - if (!isExpressionFilter(filter, withinExpr)) { + if (!isExpressionFilter(filter)) { filter = convertFilter(filter); } @@ -88,9 +82,20 @@ function createFilter(filter: any): FeatureFilter { if (compiled.result === 'error') { throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', ')); } else { + const needGeometry = filterNeedGeometry(filter); return {filter: (globalProperties: GlobalProperties, feature: Feature, canonical?: CanonicalTileID) => compiled.value.evaluate(globalProperties, feature, {}, canonical), - needGeometry: withinExpr}; + needGeometry}; + } +} + +function filterNeedGeometry(filter) { + if (filter === true || filter === false) { + return false; + } + if (!Array.isArray(filter) || filter.length === 0) { + return false; } + return filter[0] === 'within'; } // Comparison function to sort numbers and strings diff --git a/test/unit/style-spec/feature_filter.test.js b/test/unit/style-spec/feature_filter.test.js index 0bb574b67b0..aad3d061cde 100644 --- a/test/unit/style-spec/feature_filter.test.js +++ b/test/unit/style-spec/feature_filter.test.js @@ -1,10 +1,13 @@ import {test} from '../../util/test'; import createFilter from '../../../src/style-spec/feature_filter'; import convertFilter from '../../../src/style-spec/feature_filter/convert'; +import Point from '@mapbox/point-geometry'; +import MercatorCoordinate from '../../../src/geo/mercator_coordinate'; +import EXTENT from '../../../src/data/extent'; test('filter', t => { t.test('expression, zoom', (t) => { - const f = createFilter(['>=', ['number', ['get', 'x']], ['zoom']]); + const f = createFilter(['>=', ['number', ['get', 'x']], ['zoom']]).filter; t.equal(f({zoom: 1}, {properties: {x: 0}}), false); t.equal(f({zoom: 1}, {properties: {x: 1.5}}), true); t.equal(f({zoom: 1}, {properties: {x: 2.5}}), true); @@ -16,7 +19,7 @@ test('filter', t => { t.test('expression, compare two properties', (t) => { t.stub(console, 'warn'); - const f = createFilter(['==', ['string', ['get', 'x']], ['string', ['get', 'y']]]); + const f = createFilter(['==', ['string', ['get', 'x']], ['string', ['get', 'y']]]).filter; t.equal(f({zoom: 0}, {properties: {x: 1, y: 1}}), false); t.equal(f({zoom: 0}, {properties: {x: '1', y: '1'}}), true); t.equal(f({zoom: 0}, {properties: {x: 'same', y: 'same'}}), true); @@ -26,12 +29,12 @@ test('filter', t => { }); t.test('expression, collator comparison', (t) => { - const caseSensitive = createFilter(['==', ['string', ['get', 'x']], ['string', ['get', 'y']], ['collator', {'case-sensitive': true}]]); + const caseSensitive = createFilter(['==', ['string', ['get', 'x']], ['string', ['get', 'y']], ['collator', {'case-sensitive': true}]]).filter; t.equal(caseSensitive({zoom: 0}, {properties: {x: 'a', y: 'b'}}), false); t.equal(caseSensitive({zoom: 0}, {properties: {x: 'a', y: 'A'}}), false); t.equal(caseSensitive({zoom: 0}, {properties: {x: 'a', y: 'a'}}), true); - const caseInsensitive = createFilter(['==', ['string', ['get', 'x']], ['string', ['get', 'y']], ['collator', {'case-sensitive': false}]]); + const caseInsensitive = createFilter(['==', ['string', ['get', 'x']], ['string', ['get', 'y']], ['collator', {'case-sensitive': false}]]).filter; t.equal(caseInsensitive({zoom: 0}, {properties: {x: 'a', y: 'b'}}), false); t.equal(caseInsensitive({zoom: 0}, {properties: {x: 'a', y: 'A'}}), true); t.equal(caseInsensitive({zoom: 0}, {properties: {x: 'a', y: 'a'}}), true); @@ -39,14 +42,14 @@ test('filter', t => { }); t.test('expression, any/all', (t) => { - t.equal(createFilter(['all'])(), true); - t.equal(createFilter(['all', true])(), true); - t.equal(createFilter(['all', true, false])(), false); - t.equal(createFilter(['all', true, true])(), true); - t.equal(createFilter(['any'])(), false); - t.equal(createFilter(['any', true])(), true); - t.equal(createFilter(['any', true, false])(), true); - t.equal(createFilter(['any', false, false])(), false); + t.equal(createFilter(['all']).filter(), true); + t.equal(createFilter(['all', true]).filter(), true); + t.equal(createFilter(['all', true, false]).filter(), false); + t.equal(createFilter(['all', true, true]).filter(), true); + t.equal(createFilter(['any']).filter(), false); + t.equal(createFilter(['any', true]).filter(), true); + t.equal(createFilter(['any', true, false]).filter(), true); + t.equal(createFilter(['any', false, false]).filter(), false); t.end(); }); @@ -66,6 +69,26 @@ test('filter', t => { t.end(); }); + t.test('expression, within', (t) => { + const getPointFromLngLat = (lng, lat, canonical) => { + const p = MercatorCoordinate.fromLngLat({lng, lat}, 0); + const tilesAtZoom = Math.pow(2, canonical.z); + return new Point( + (p.x * tilesAtZoom - canonical.x) * EXTENT, + (p.y * tilesAtZoom - canonical.y) * EXTENT); + }; + const withinFilter = createFilter(['within', {'type': 'Polygon', 'coordinates': [[[0, 0], [5, 0], [5, 5], [0, 5], [0, 0]]]}]); + t.equal(withinFilter.needGeometry, true); + const canonical = {z: 3, x: 3, y:3}; + t.equal(withinFilter.filter({zoom: 3}, {type: 1, geometry: [[getPointFromLngLat(2, 2, canonical)]]}, canonical), true); + t.equal(withinFilter.filter({zoom: 3}, {type: 1, geometry: [[getPointFromLngLat(6, 6, canonical)]]}, canonical), false); + t.equal(withinFilter.filter({zoom: 3}, {type: 1, geometry: [[getPointFromLngLat(5, 5, canonical)]]}, canonical), false); + t.equal(withinFilter.filter({zoom: 3}, {type: 2, geometry: [[getPointFromLngLat(2, 2, canonical), getPointFromLngLat(3, 3, canonical)]]}, canonical), true); + t.equal(withinFilter.filter({zoom: 3}, {type: 2, geometry: [[getPointFromLngLat(6, 6, canonical), getPointFromLngLat(2, 2, canonical)]]}, canonical), false); + t.equal(withinFilter.filter({zoom: 3}, {type: 2, geometry: [[getPointFromLngLat(5, 5, canonical), getPointFromLngLat(2, 2, canonical)]]}, canonical), false); + t.end(); + }); + legacyFilterTests(t, createFilter); t.end(); @@ -89,7 +112,7 @@ test('convert legacy filters to expressions', t => { ]; const converted = convertFilter(filter); - const f = createFilter(converted); + const f = createFilter(converted).filter; t.equal(f({zoom: 0}, {properties: {x: 0, y: 1, z: 1}}), true); t.equal(f({zoom: 0}, {properties: {x: 1, y: 0, z: 1}}), true); @@ -166,23 +189,23 @@ test('convert legacy filters to expressions', t => { t.end(); }); -function legacyFilterTests(t, filter) { +function legacyFilterTests(t, createFilterExpr) { t.test('degenerate', (t) => { - t.equal(filter()(), true); - t.equal(filter(undefined)(), true); - t.equal(filter(null)(), true); + t.equal(createFilterExpr().filter(), true); + t.equal(createFilterExpr(undefined).filter(), true); + t.equal(createFilterExpr(null).filter(), true); t.end(); }); t.test('==, string', (t) => { - const f = filter(['==', 'foo', 'bar']); + const f = createFilterExpr(['==', 'foo', 'bar']).filter; t.equal(f({zoom: 0}, {properties: {foo: 'bar'}}), true); t.equal(f({zoom: 0}, {properties: {foo: 'baz'}}), false); t.end(); }); t.test('==, number', (t) => { - const f = filter(['==', 'foo', 0]); + const f = createFilterExpr(['==', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), false); @@ -195,7 +218,7 @@ function legacyFilterTests(t, filter) { }); t.test('==, null', (t) => { - const f = filter(['==', 'foo', null]); + const f = createFilterExpr(['==', 'foo', null]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), false); @@ -208,14 +231,14 @@ function legacyFilterTests(t, filter) { }); t.test('==, $type', (t) => { - const f = filter(['==', '$type', 'LineString']); + const f = createFilterExpr(['==', '$type', 'LineString']).filter; t.equal(f({zoom: 0}, {type: 1}), false); t.equal(f({zoom: 0}, {type: 2}), true); t.end(); }); t.test('==, $id', (t) => { - const f = filter(['==', '$id', 1234]); + const f = createFilterExpr(['==', '$id', 1234]).filter; t.equal(f({zoom: 0}, {id: 1234}), true); t.equal(f({zoom: 0}, {id: '1234'}), false); @@ -225,14 +248,14 @@ function legacyFilterTests(t, filter) { }); t.test('!=, string', (t) => { - const f = filter(['!=', 'foo', 'bar']); + const f = createFilterExpr(['!=', 'foo', 'bar']).filter; t.equal(f({zoom: 0}, {properties: {foo: 'bar'}}), false); t.equal(f({zoom: 0}, {properties: {foo: 'baz'}}), true); t.end(); }); t.test('!=, number', (t) => { - const f = filter(['!=', 'foo', 0]); + const f = createFilterExpr(['!=', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), true); @@ -245,7 +268,7 @@ function legacyFilterTests(t, filter) { }); t.test('!=, null', (t) => { - const f = filter(['!=', 'foo', null]); + const f = createFilterExpr(['!=', 'foo', null]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), true); @@ -258,14 +281,14 @@ function legacyFilterTests(t, filter) { }); t.test('!=, $type', (t) => { - const f = filter(['!=', '$type', 'LineString']); + const f = createFilterExpr(['!=', '$type', 'LineString']).filter; t.equal(f({zoom: 0}, {type: 1}), true); t.equal(f({zoom: 0}, {type: 2}), false); t.end(); }); t.test('<, number', (t) => { - const f = filter(['<', 'foo', 0]); + const f = createFilterExpr(['<', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: -1}}), true); @@ -281,7 +304,7 @@ function legacyFilterTests(t, filter) { }); t.test('<, string', (t) => { - const f = filter(['<', 'foo', '0']); + const f = createFilterExpr(['<', 'foo', '0']).filter; t.equal(f({zoom: 0}, {properties: {foo: -1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); @@ -296,7 +319,7 @@ function legacyFilterTests(t, filter) { }); t.test('<=, number', (t) => { - const f = filter(['<=', 'foo', 0]); + const f = createFilterExpr(['<=', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: -1}}), true); @@ -312,7 +335,7 @@ function legacyFilterTests(t, filter) { }); t.test('<=, string', (t) => { - const f = filter(['<=', 'foo', '0']); + const f = createFilterExpr(['<=', 'foo', '0']).filter; t.equal(f({zoom: 0}, {properties: {foo: -1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); @@ -327,7 +350,7 @@ function legacyFilterTests(t, filter) { }); t.test('>, number', (t) => { - const f = filter(['>', 'foo', 0]); + const f = createFilterExpr(['>', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: -1}}), false); @@ -343,7 +366,7 @@ function legacyFilterTests(t, filter) { }); t.test('>, string', (t) => { - const f = filter(['>', 'foo', '0']); + const f = createFilterExpr(['>', 'foo', '0']).filter; t.equal(f({zoom: 0}, {properties: {foo: -1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); @@ -358,7 +381,7 @@ function legacyFilterTests(t, filter) { }); t.test('>=, number', (t) => { - const f = filter(['>=', 'foo', 0]); + const f = createFilterExpr(['>=', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: -1}}), false); @@ -374,7 +397,7 @@ function legacyFilterTests(t, filter) { }); t.test('>=, string', (t) => { - const f = filter(['>=', 'foo', '0']); + const f = createFilterExpr(['>=', 'foo', '0']).filter; t.equal(f({zoom: 0}, {properties: {foo: -1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); @@ -389,13 +412,13 @@ function legacyFilterTests(t, filter) { }); t.test('in, degenerate', (t) => { - const f = filter(['in', 'foo']); + const f = createFilterExpr(['in', 'foo']).filter; t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.end(); }); t.test('in, string', (t) => { - const f = filter(['in', 'foo', '0']); + const f = createFilterExpr(['in', 'foo', '0']).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), true); t.equal(f({zoom: 0}, {properties: {foo: true}}), false); @@ -407,7 +430,7 @@ function legacyFilterTests(t, filter) { }); t.test('in, number', (t) => { - const f = filter(['in', 'foo', 0]); + const f = createFilterExpr(['in', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), false); t.equal(f({zoom: 0}, {properties: {foo: true}}), false); @@ -418,7 +441,7 @@ function legacyFilterTests(t, filter) { }); t.test('in, null', (t) => { - const f = filter(['in', 'foo', null]); + const f = createFilterExpr(['in', 'foo', null]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), false); t.equal(f({zoom: 0}, {properties: {foo: true}}), false); @@ -429,7 +452,7 @@ function legacyFilterTests(t, filter) { }); t.test('in, multiple', (t) => { - const f = filter(['in', 'foo', 0, 1]); + const f = createFilterExpr(['in', 'foo', 0, 1]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: 3}}), false); @@ -439,7 +462,7 @@ function legacyFilterTests(t, filter) { t.test('in, large_multiple', (t) => { const values = Array.from({length: 2000}).map(Number.call, Number); values.reverse(); - const f = filter(['in', 'foo'].concat(values)); + const f = createFilterExpr(['in', 'foo'].concat(values)).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: 1999}}), true); @@ -451,7 +474,7 @@ function legacyFilterTests(t, filter) { const values = Array.from({length: 2000}).map(Number.call, Number); values.push('a'); values.unshift('b'); - const f = filter(['in', 'foo'].concat(values)); + const f = createFilterExpr(['in', 'foo'].concat(values)).filter; t.equal(f({zoom: 0}, {properties: {foo: 'b'}}), true); t.equal(f({zoom: 0}, {properties: {foo: 'a'}}), true); t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); @@ -462,12 +485,12 @@ function legacyFilterTests(t, filter) { }); t.test('in, $type', (t) => { - const f = filter(['in', '$type', 'LineString', 'Polygon']); + const f = createFilterExpr(['in', '$type', 'LineString', 'Polygon']).filter; t.equal(f({zoom: 0}, {type: 1}), false); t.equal(f({zoom: 0}, {type: 2}), true); t.equal(f({zoom: 0}, {type: 3}), true); - const f1 = filter(['in', '$type', 'Polygon', 'LineString', 'Point']); + const f1 = createFilterExpr(['in', '$type', 'Polygon', 'LineString', 'Point']).filter; t.equal(f1({zoom: 0}, {type: 1}), true); t.equal(f1({zoom: 0}, {type: 2}), true); t.equal(f1({zoom: 0}, {type: 3}), true); @@ -476,13 +499,13 @@ function legacyFilterTests(t, filter) { }); t.test('!in, degenerate', (t) => { - const f = filter(['!in', 'foo']); + const f = createFilterExpr(['!in', 'foo']).filter; t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.end(); }); t.test('!in, string', (t) => { - const f = filter(['!in', 'foo', '0']); + const f = createFilterExpr(['!in', 'foo', '0']).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), false); t.equal(f({zoom: 0}, {properties: {foo: null}}), true); @@ -492,7 +515,7 @@ function legacyFilterTests(t, filter) { }); t.test('!in, number', (t) => { - const f = filter(['!in', 'foo', 0]); + const f = createFilterExpr(['!in', 'foo', 0]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), true); t.equal(f({zoom: 0}, {properties: {foo: null}}), true); @@ -501,7 +524,7 @@ function legacyFilterTests(t, filter) { }); t.test('!in, null', (t) => { - const f = filter(['!in', 'foo', null]); + const f = createFilterExpr(['!in', 'foo', null]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), true); t.equal(f({zoom: 0}, {properties: {foo: null}}), false); @@ -510,7 +533,7 @@ function legacyFilterTests(t, filter) { }); t.test('!in, multiple', (t) => { - const f = filter(['!in', 'foo', 0, 1]); + const f = createFilterExpr(['!in', 'foo', 0, 1]).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 3}}), true); @@ -518,7 +541,7 @@ function legacyFilterTests(t, filter) { }); t.test('!in, large_multiple', (t) => { - const f = filter(['!in', 'foo'].concat(Array.from({length: 2000}).map(Number.call, Number))); + const f = createFilterExpr(['!in', 'foo'].concat(Array.from({length: 2000}).map(Number.call, Number))).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1999}}), false); @@ -527,7 +550,7 @@ function legacyFilterTests(t, filter) { }); t.test('!in, $type', (t) => { - const f = filter(['!in', '$type', 'LineString', 'Polygon']); + const f = createFilterExpr(['!in', '$type', 'LineString', 'Polygon']).filter; t.equal(f({zoom: 0}, {type: 1}), true); t.equal(f({zoom: 0}, {type: 2}), false); t.equal(f({zoom: 0}, {type: 3}), false); @@ -535,55 +558,55 @@ function legacyFilterTests(t, filter) { }); t.test('any', (t) => { - const f1 = filter(['any']); + const f1 = createFilterExpr(['any']).filter; t.equal(f1({zoom: 0}, {properties: {foo: 1}}), false); - const f2 = filter(['any', ['==', 'foo', 1]]); + const f2 = createFilterExpr(['any', ['==', 'foo', 1]]).filter; t.equal(f2({zoom: 0}, {properties: {foo: 1}}), true); - const f3 = filter(['any', ['==', 'foo', 0]]); + const f3 = createFilterExpr(['any', ['==', 'foo', 0]]).filter; t.equal(f3({zoom: 0}, {properties: {foo: 1}}), false); - const f4 = filter(['any', ['==', 'foo', 0], ['==', 'foo', 1]]); + const f4 = createFilterExpr(['any', ['==', 'foo', 0], ['==', 'foo', 1]]).filter; t.equal(f4({zoom: 0}, {properties: {foo: 1}}), true); t.end(); }); t.test('all', (t) => { - const f1 = filter(['all']); + const f1 = createFilterExpr(['all']).filter; t.equal(f1({zoom: 0}, {properties: {foo: 1}}), true); - const f2 = filter(['all', ['==', 'foo', 1]]); + const f2 = createFilterExpr(['all', ['==', 'foo', 1]]).filter; t.equal(f2({zoom: 0}, {properties: {foo: 1}}), true); - const f3 = filter(['all', ['==', 'foo', 0]]); + const f3 = createFilterExpr(['all', ['==', 'foo', 0]]).filter; t.equal(f3({zoom: 0}, {properties: {foo: 1}}), false); - const f4 = filter(['all', ['==', 'foo', 0], ['==', 'foo', 1]]); + const f4 = createFilterExpr(['all', ['==', 'foo', 0], ['==', 'foo', 1]]).filter; t.equal(f4({zoom: 0}, {properties: {foo: 1}}), false); t.end(); }); t.test('none', (t) => { - const f1 = filter(['none']); + const f1 = createFilterExpr(['none']).filter; t.equal(f1({zoom: 0}, {properties: {foo: 1}}), true); - const f2 = filter(['none', ['==', 'foo', 1]]); + const f2 = createFilterExpr(['none', ['==', 'foo', 1]]).filter; t.equal(f2({zoom: 0}, {properties: {foo: 1}}), false); - const f3 = filter(['none', ['==', 'foo', 0]]); + const f3 = createFilterExpr(['none', ['==', 'foo', 0]]).filter; t.equal(f3({zoom: 0}, {properties: {foo: 1}}), true); - const f4 = filter(['none', ['==', 'foo', 0], ['==', 'foo', 1]]); + const f4 = createFilterExpr(['none', ['==', 'foo', 0], ['==', 'foo', 1]]).filter; t.equal(f4({zoom: 0}, {properties: {foo: 1}}), false); t.end(); }); t.test('has', (t) => { - const f = filter(['has', 'foo']); + const f = createFilterExpr(['has', 'foo']).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), true); t.equal(f({zoom: 0}, {properties: {foo: 1}}), true); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), true); @@ -596,7 +619,7 @@ function legacyFilterTests(t, filter) { }); t.test('!has', (t) => { - const f = filter(['!has', 'foo']); + const f = createFilterExpr(['!has', 'foo']).filter; t.equal(f({zoom: 0}, {properties: {foo: 0}}), false); t.equal(f({zoom: 0}, {properties: {foo: 1}}), false); t.equal(f({zoom: 0}, {properties: {foo: '0'}}), false);