-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(toBeFeatureCollection): add new matcher
Verifies an object is a valid GeoJSON FeatureCollection. Also updates namespaces for new core/matcher type as well as adds appropriate setup scripts and tests. Resolves: #25
- Loading branch information
1 parent
bcfb91e
commit 21fe044
Showing
14 changed files
with
990 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
const { validBoundingBox } = require('../boundingBoxes/validBoundingBox') | ||
const { feature } = require('../features/feature') | ||
|
||
/** | ||
* Verifies an object is a valid GeoJSON FeatureCollection. This object requires a "type" member that must | ||
* equal 'FeatureCollection', and a "features" member that contains either a valid GeoJSON Feature | ||
* or an empty array. | ||
* | ||
* Foreign members are allowed with the exceptions thrown below. | ||
* If present, bounding boxes must be valid. | ||
* | ||
* @memberof Core.FeatureCollections | ||
* @see https://github.com/M-Scott-Lassiter/jest-geojson/issues/25 | ||
* @param {object} featureCollectionObject a GeoJSON LineString Geometry object | ||
* @returns {boolean} True if a valid GeoJSON FeatureCollection. If invalid, it will throw an error. | ||
* @throws {Error} Argument not an object | ||
* @throws {Error} Must have a type property with value 'FeatureCollection' | ||
* @throws {Error} Forbidden from having a property 'coordinates', 'geometries', 'geometry', or 'properties' | ||
* @throws {Error} Bounding box must be valid (if present) | ||
* @example | ||
* const testFeatureCollection = { | ||
* "type": "FeatureCollection", | ||
* "features": [{ | ||
* "type": "Feature", | ||
* "geometry": { | ||
* "type": "Point", | ||
* "coordinates": [102.0, 0.5] | ||
* } | ||
* }, | ||
* ... | ||
* ] | ||
* } | ||
* const multiPoint = { | ||
* type: "MultiPoint", | ||
* coordinates: [ | ||
* [101.0, 0.0], | ||
* [102.0, 1.0] | ||
* ] | ||
* } | ||
* | ||
* const goodExample1 = featureCollection(testFeatureCollection)) // true | ||
* | ||
* const badExample1 = featureCollection(multiPoint)) // throws error | ||
* const badExample2 = featureCollection(testFeatureCollection.features)) // throws error | ||
*/ | ||
function featureCollection(featureCollectionObject) { | ||
if (typeof featureCollectionObject !== 'object') { | ||
throw new Error(`Argument must be a FeatureCollection object.`) | ||
} | ||
|
||
if (featureCollectionObject.type !== 'FeatureCollection') { | ||
throw new Error(`Must have a type property with value 'FeatureCollection'.`) | ||
} | ||
|
||
if ('coordinates' in featureCollectionObject) { | ||
throw new Error( | ||
`GeoJSON FeatureCollection objects are forbidden from having a property 'coordinates'.` | ||
) | ||
} | ||
|
||
if ('geometries' in featureCollectionObject) { | ||
throw new Error( | ||
`GeoJSON FeatureCollection objects are forbidden from having a property 'geometries'.` | ||
) | ||
} | ||
|
||
if ('geometry' in featureCollectionObject) { | ||
throw new Error( | ||
`GeoJSON FeatureCollection objects are forbidden from having a property 'geometry'.` | ||
) | ||
} | ||
|
||
if ('properties' in featureCollectionObject) { | ||
throw new Error( | ||
`GeoJSON FeatureCollection objects are forbidden from having a property 'properties'.` | ||
) | ||
} | ||
|
||
if (!('features' in featureCollectionObject)) { | ||
throw new Error(`GeoJSON FeatureCollection objects must have a property 'features'.`) | ||
} | ||
|
||
if (!Array.isArray(featureCollectionObject.features)) { | ||
throw new Error( | ||
`GeoJSON FeatureCollection features must be either an array of valid Feature objects or an empty array.` | ||
) | ||
} | ||
|
||
// if (typeof featureCollectionObject.geometry !== 'object' || Array.isArray(featureCollectionObject.geometry)) { | ||
// throw new Error(`GeoJSON Feature 'geometry' must be a valid GeoJSON geometry object.`) | ||
// } | ||
|
||
if ('bbox' in featureCollectionObject) { | ||
validBoundingBox(featureCollectionObject.bbox) | ||
} | ||
|
||
// if ('id' in featureCollectionObject) { | ||
// if ( | ||
// !(typeof featureCollectionObject.id === 'number' || typeof featureCollectionObject.id === 'string') || | ||
// Number.isNaN(featureCollectionObject.id) | ||
// ) { | ||
// throw new Error(`If present, ID must be either a number or string.`) | ||
// } | ||
// } | ||
|
||
// // Guard clause; features are allowed to have null geometry. However, if the matcher explicitly calls | ||
// // for a particular geometry type, null isn't an option. We have to check for that. | ||
// if (featureCollectionObject.geometry === null && geometryType === undefined) { | ||
// return true | ||
// } | ||
|
||
// // At this point, we have guaranteed there is a features array here. Validate each element with the core functions. | ||
featureCollectionObject.features.forEach((featureObject) => { | ||
feature(featureObject) | ||
}) | ||
|
||
return true | ||
} | ||
|
||
exports.featureCollection = featureCollection |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
const { featureCollection } = require('../../core/featureCollections/featureCollection') | ||
|
||
// eslint-disable-next-line jsdoc/require-returns | ||
/** | ||
* Verifies an object is a valid GeoJSON FeatureCollection. This object requires a "type" member that must | ||
* equal 'FeatureCollection', and a "features" member that contains either a valid GeoJSON Feature | ||
* or an empty array. | ||
* | ||
* Foreign members are allowed with the exception of 'coordinates', 'geometries', 'geometry', or 'properties'. | ||
* If present, bounding boxes must be valid. | ||
* | ||
* @memberof Matchers.FeatureCollections | ||
* @see https://github.com/M-Scott-Lassiter/jest-geojson/issues/25 | ||
* @param {object} featureCollectionObject any GeoJSON Feature object | ||
* @example | ||
* const testFeatureCollection = { | ||
* "type": "FeatureCollection", | ||
* "features": [{ | ||
* "type": "Feature", | ||
* "geometry": { | ||
* "type": "Point", | ||
* "coordinates": [102.0, 0.5] | ||
* } | ||
* }, | ||
* ... | ||
* ] | ||
* } | ||
* test('Object is valid GeoJSON Feature', () => { | ||
* expect(testFeatureCollection).toBeFeatureCollection() | ||
* }) | ||
* @example | ||
* const multiPoint = { | ||
* type: "MultiPoint", | ||
* coordinates: [ | ||
* [101.0, 0.0], | ||
* [102.0, 1.0] | ||
* ] | ||
* } | ||
* | ||
* test('Object is NOT valid GeoJSON Geometry Object', () => { | ||
* expect(multiPoint).not.toBeFeatureCollection() | ||
* expect(testFeatureCollection.features).not.toBeFeatureCollection() | ||
* }) | ||
*/ | ||
function toBeFeatureCollection(featureCollectionObject) { | ||
const { printReceived, matcherHint } = this.utils | ||
const passMessage = | ||
// eslint-disable-next-line prefer-template | ||
matcherHint('.not.toBeFeatureCollection', 'FeatureCollectionObject', '') + | ||
'\n\n' + | ||
`Expected input to not be a valid GeoJSON FeatureCollection object.\n\n` + | ||
`Received: ${printReceived(featureCollectionObject)}` | ||
|
||
/** | ||
* Combines a custom error message with built in Jest tools to provide a more descriptive error | ||
* meessage to the end user. | ||
* | ||
* @param {string} errorMessage Error message text to return to the user | ||
* @returns {string} Concatenated Jest test result string | ||
*/ | ||
function failMessage(errorMessage) { | ||
return ( | ||
// eslint-disable-next-line prefer-template, no-unused-expressions | ||
matcherHint('.toBeFeatureCollection', 'FeatureObject', 'GeometryType') + | ||
'\n\n' + | ||
`${errorMessage}\n\n` + | ||
`Received: ${printReceived(featureCollectionObject)}` | ||
) | ||
} | ||
|
||
try { | ||
featureCollection(featureCollectionObject) | ||
} catch (err) { | ||
return { pass: false, message: () => failMessage(err.message) } | ||
} | ||
return { pass: true, message: () => passMessage } | ||
} | ||
|
||
exports.toBeFeatureCollection = toBeFeatureCollection |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const matchers = require('../matchers') | ||
const { throwJestRuntimeError } = require('./all') | ||
|
||
const jestExpect = global.expect | ||
|
||
if (jestExpect !== undefined) { | ||
expect.extend(matchers.featureCollections) | ||
} else { | ||
throwJestRuntimeError() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.