Skip to content

Commit

Permalink
feat(toBeLineStringGeometry): add new matcher
Browse files Browse the repository at this point in the history
Verifies an object is a valid GeoJSON LineString Geometry.

Resolves: #11
  • Loading branch information
M-Scott-Lassiter committed May 27, 2022
1 parent 4db12b0 commit 54416a5
Show file tree
Hide file tree
Showing 12 changed files with 536 additions and 15 deletions.
1 change: 1 addition & 0 deletions .cz-config.js
Expand Up @@ -7,6 +7,7 @@ const coordinateMatchers = [
{ name: 'isValid3DCoordinate' },
{ name: 'isValidBoundingBox' },
{ name: 'isValidCoordinate' },
{ name: 'toBeLineStringGeometry' },
{ name: 'toBeMultiPointGeometry' },
{ name: 'toBePointGeometry' }
]
Expand Down
9 changes: 4 additions & 5 deletions CONTRIBUTING.md
Expand Up @@ -88,16 +88,15 @@ To submit a pull request,
- [ ] Create a core function under `src/core/<category>`
- [ ] Document the function using JSDoc. Refer to the issue.
- [ ] Register the core function in `src/core.js`
- [ ] Add a verification test to `tests/core.test.js`
- <u>Create Matcher Function</u>
- [ ] Create a matcher function under `src/matchers/<category>`
- [ ] Document the matcher using JSDoc. Refer to the issue.
- [ ] Register the matcher in `src/matchers.js`
- [ ] Add a verification test to `matchers.test.js`
- [ ] Add the matcher to the `.cz-config.js` list (alphabetical order under the `coordinateMatchers` variable)
- <u>Add Testing</u>
- [ ] Create a test for the matcher under `tests/<category>`
- [ ] Add a test to `tests/core.test.js`
- [ ] Add a test to `matchers.test.js`
- [ ] Verify all tests pass and have 100% coverage
- [ ] Create a test for the matcher under `tests/<category>`
- [ ] Verify all tests pass and have 100% coverage
- [ ] Add the matcher to the README.md list (alphabetical order within category)
- [ ] Run the `build` script locally
- [ ] Push to Github then open pull request
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -157,7 +157,7 @@ _1.0.0_

- [x] toBePointGeometry
- [x] toBeMultiPointGeometry
- [ ] toBeLineStringGeometry
- [x] toBeLineStringGeometry
- [ ] toBeMultiLineStringGeometry
- [ ] toBePolygonGeometry
- [ ] toBeMultiPolygonGeometry
Expand Down
5 changes: 3 additions & 2 deletions src/core.js
Expand Up @@ -13,6 +13,7 @@ exports.coordinates = {
}

exports.geometries = {
pointGeometry: require('./core/geometries/pointGeometry'),
multiPointGeometry: require('./core/geometries/multiPointGeometry')
lineStringGeometry: require('./core/geometries/lineStringGeometry'),
multiPointGeometry: require('./core/geometries/multiPointGeometry'),
pointGeometry: require('./core/geometries/pointGeometry')
}
83 changes: 83 additions & 0 deletions src/core/geometries/lineStringGeometry.js
@@ -0,0 +1,83 @@
const { validCoordinate } = require('../coordinates/validCoordinate')

/**
* Verifies an object is a valid GeoJSON LineString Geometry. This geometry requires a
* 'type' property that must equal "LineString", and a 'coordinates' property that contains
* an array of valid WGS-84 GeoJSON coordinate(s). The coordinates may be an empty array,
* but may not be an array of empty arrays.
*
* Foreign members are allowed with the exceptions thrown below.
*
* @memberof Core.Geometries
* @see https://github.com/M-Scott-Lassiter/jest-geojson/issues/11
* @param {object} geometryObject a GeoJSON Multi Point Geometry object
* @returns {boolean} True if a valid GeoJSON Multi Point Geometry. If invalid, it will throw an error.
* @throws {Error} Argument not an object
* @throws {Error} Must have a type property with value 'LineString'
* @throws {Error} forbidden from having a property 'geometry', 'properties', or 'features'
* @example
* const linestring = {
"type": "LineString",
"coordinates": [
[
[180.0, 40.0], [180.0, 50.0], [170.0, 50.0],
[170.0, 40.0], [180.0, 40.0]
]
]
}
const point = {
type: "Point",
coordinates: [100.0, 0.0]
}
console.log(lineStringGeometry(linestring)) // true
console.log(lineStringGeometry(point)) // throws error
*/
function lineStringGeometry(geometryObject) {
if (
typeof geometryObject !== 'object' ||
Array.isArray(geometryObject) ||
geometryObject === null
) {
throw new Error('Argument must be a GeoJSON LineString Geometry object.')
}

if (!('coordinates' in geometryObject)) {
throw new Error(`GeoJSON LineString Geometry must contain a 'coordinates' property.`)
}

if (geometryObject.type !== 'LineString') {
throw new Error(`Must have a type property with value 'LineString'`)
}

if ('geometry' in geometryObject) {
throw new Error(
`GeoJSON LineString Geometry objects are forbidden from having a property 'geometry'.`
)
}

if ('properties' in geometryObject) {
throw new Error(
`GeoJSON LineString Geometry objects are forbidden from having a property 'properties'.`
)
}

if ('features' in geometryObject) {
throw new Error(
`GeoJSON LineString Geometry objects are forbidden from having a property 'features'.`
)
}

// // Geometry objects are allowed to have empty arrays as coordinates, however validCoordinate may not.
// If coordinates is an empty array, we're done. Otherwise, check for coordinate validity.
if (!Array.isArray(geometryObject.coordinates) && geometryObject.coordinates.length !== 1) {
throw new Error('Coordinates property must be an array of valid GeoJSON coordinates')
}
for (let i = 0; i < geometryObject.coordinates.length; i++) {
validCoordinate(geometryObject.coordinates[i])
}

return true
}

exports.lineStringGeometry = lineStringGeometry
3 changes: 0 additions & 3 deletions src/core/geometries/multiPointGeometry.js
Expand Up @@ -66,9 +66,6 @@ function multiPointGeometry(geometryObject) {

// Geometry objects are allowed to have empty arrays as coordinates, however validCoordinate may not.
// If coordinates is an empty array, we're done. Otherwise, check for coordinate validity.
// if (Array.isArray(geometryObject.coordinates) && geometryObject.coordinates.length === 0) {
// return true
// }
if (!Array.isArray(geometryObject.coordinates) && geometryObject.coordinates.length !== 1) {
throw new Error('Coordinates property must be an array of valid GeoJSON coordinates')
}
Expand Down
6 changes: 4 additions & 2 deletions src/matchers.js
Expand Up @@ -22,9 +22,11 @@ exports.coordinates = {

// Geometries
exports.geometries = {
toBePointGeometry: require('./matchers/geometries/toBePointGeometry').toBePointGeometry,
toBeLineStringGeometry: require('./matchers/geometries/toBeLineStringGeometry')
.toBeLineStringGeometry,
toBeMultiPointGeometry: require('./matchers/geometries/toBeMultiPointGeometry')
.toBeMultiPointGeometry
.toBeMultiPointGeometry,
toBePointGeometry: require('./matchers/geometries/toBePointGeometry').toBePointGeometry
}

// Properties
Expand Down
68 changes: 68 additions & 0 deletions src/matchers/geometries/toBeLineStringGeometry.js
@@ -0,0 +1,68 @@
const { lineStringGeometry } = require('../../core/geometries/lineStringGeometry')

// eslint-disable-next-line jsdoc/require-returns
/**
* Verifies an object is a valid GeoJSON LineString Geometry. This geometry requires a
* 'type' property that must equal "LineString", and a 'coordinates' property that contains
* an array of valid WGS-84 GeoJSON coordinate(s). The coordinates may be an empty array,
* but may not be an array of empty arrays.
*
* Foreign members are allowed with the exception of 'geometry', 'properties', or 'features'.
*
* @memberof Matchers.Geometries
* @see https://github.com/M-Scott-Lassiter/jest-geojson/issues/11
* @param {object} geometryObject a GeoJSON MultiPoint Geometry object
* @example
const linestring = {
"type": "LineString",
"coordinates": [
[
[180.0, 40.0], [180.0, 50.0], [170.0, 50.0],
[170.0, 40.0], [180.0, 40.0]
]
]
}
const point = {
type: "Point",
coordinates: [100.0, 0.0]
}
expect(linestring).toBeLineStringGeometry()
expect(point).not.toBeLineStringGeometry()
*/
function toBeLineStringGeometry(geometryObject) {
const { printReceived, matcherHint } = this.utils
const passMessage =
// eslint-disable-next-line prefer-template
matcherHint('.not.toBeLineStringGeometry', 'GeometryObject', '') +
'\n\n' +
`Expected input to not be a valid GeoJSON LineString geometry.\n\n` +
`Received: ${printReceived(geometryObject)}`

/**
* 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('.toBeLineStringGeometry', 'GeometryObject', '') +
'\n\n' +
`${errorMessage}\n\n` +
`Received: ${printReceived(geometryObject)}`
)
}

try {
lineStringGeometry(geometryObject)
} catch (err) {
return { pass: false, message: () => failMessage(err.message) }
}
return { pass: true, message: () => passMessage }
}

exports.toBeLineStringGeometry = toBeLineStringGeometry
8 changes: 6 additions & 2 deletions tests/core.test.js
Expand Up @@ -31,11 +31,15 @@ describe('Coordinate Functions Exported', () => {
})

describe('Geometry Functions Exported', () => {
test('valid2DBoundingBox', () => {
test('lineStringGeometry', () => {
expect('lineStringGeometry' in core.geometries).toBeTruthy()
})

test('multiPointGeometry', () => {
expect('multiPointGeometry' in core.geometries).toBeTruthy()
})

test('valid3DBoundingBox', () => {
test('pointGeometry', () => {
expect('pointGeometry' in core.geometries).toBeTruthy()
})
})
17 changes: 17 additions & 0 deletions tests/geometries/__snapshots__/toBeLineStringGeometry.test.js.snap
@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Error Snapshot Testing. Throws error: expect({type: 'LineString', coordinates: [[0, 0]]}).not.toBeLineStringGeometry 1`] = `
"expect(GeometryObject).not.toBeLineStringGeometry()
Expected input to not be a valid GeoJSON LineString geometry.
Received: {\\"coordinates\\": [[0, 0]], \\"type\\": \\"LineString\\"}"
`;

exports[`Error Snapshot Testing. Throws error: expect(false).toBeLineStringGeometry() 1`] = `
"expect(GeometryObject).toBeLineStringGeometry()
Argument must be a GeoJSON LineString Geometry object.
Received: false"
`;

0 comments on commit 54416a5

Please sign in to comment.