From 48264869e79e9745cb6cab03815d5d14fae6aa2d Mon Sep 17 00:00:00 2001 From: Stephan Besser Date: Wed, 4 Dec 2024 14:42:31 +0100 Subject: [PATCH] refactor: remove redundant tests for unknown formats in coordinate parsers and update README with additional examples --- README.md | 13 ++- .../dm-unsigned-prefixed-hemisphere-format.ts | 3 - .../dm-unsigned-suffixed-hemisphere-format.ts | 3 - .../dms-signed-prefixed-hemisphere-format.ts | 81 ++++++++++++++ .../dms-signed-suffixed-hemisphere-format.ts | 81 ++++++++++++++ src/parser.ts | 4 + tests/decimal-signed-format.test.ts | 4 - ...-signed-prefixed-hemisphere-format.test.ts | 6 -- ...-signed-suffixed-hemisphere-format.test.ts | 6 -- tests/decimal-unsigned-format.test.ts | 4 - ...nsigned-prefixed-hemisphere-format.test.ts | 4 - ...nsigned-suffixed-hemisphere-format.test.ts | 4 - ...nsigned-prefixed-hemisphere-format.test.ts | 6 -- ...nsigned-suffixed-hemisphere-format.test.ts | 6 -- tests/dms-signed-format.test.ts | 4 - ...s-signed-prefixed-hemisphereformat.test.ts | 65 +++++++++++ ...s-signed-suffixed-hemisphereformat.test.ts | 65 +++++++++++ tests/dms-unsigned-format.test.ts | 4 - tests/parser.test.ts | 102 +++++++++++++++++- 19 files changed, 406 insertions(+), 59 deletions(-) create mode 100644 src/formats/dms-signed-prefixed-hemisphere-format.ts create mode 100644 src/formats/dms-signed-suffixed-hemisphere-format.ts create mode 100644 tests/dms-signed-prefixed-hemisphereformat.test.ts create mode 100644 tests/dms-signed-suffixed-hemisphereformat.test.ts diff --git a/README.md b/README.md index 04a3c5f..f64bce3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # OpenAIP Coordinate Parser -Easily extendable and configurable parser for NodeJS and the browser that extracts coordinates from a variety of formatted lat/lon strings. +Easily extendable and configurable parser for NodeJS and the browser that extracts coordinates from a variety of formatted lat/lon strings. The main focus is parsing various decimal or DMS format variations. Contributions that +add other format parsers are always welcome! ### Usage @@ -113,7 +114,11 @@ Currently the out-of-the-box format parsers supports various formats and handles - `40 7 23 -74 7 23` - `40 7 23, -74 7 23` - `40 7 23.123, -74 7 23.123` -- `` -- `` -- `` +- `40°7'23"N 74°7'23"W` +- `40°7'23"N, 74°7'23"W` +- `40°7'23.123"N 74°7'23.123"W` +- `N40°7'23" W74°7'23"` +- `N40°7'23", W74°7'23"` +- `N40°7'23"W74°7'23"` +- `N 40°7'23.123" W 74°7'23.123"` - `` diff --git a/src/formats/dm-unsigned-prefixed-hemisphere-format.ts b/src/formats/dm-unsigned-prefixed-hemisphere-format.ts index 4113dad..7191f7a 100644 --- a/src/formats/dm-unsigned-prefixed-hemisphere-format.ts +++ b/src/formats/dm-unsigned-prefixed-hemisphere-format.ts @@ -49,9 +49,6 @@ export class DmUnsignedPrefixedHemisphereFormat extends BaseFormat { /** * Converts a DMS notation coordinate like "4007.38N" to DMS parts. - * - * @param {string} value - The parsed DMS value, e.g. "4007.38N" or "74007.38W" - * @return {import('../types').openaip.CoordinateParser.DmsCoordinate} */ toDms(value: string): DmsCoordinate { validateSchema(value, z.string(), { assert: true, name: 'value' }); diff --git a/src/formats/dm-unsigned-suffixed-hemisphere-format.ts b/src/formats/dm-unsigned-suffixed-hemisphere-format.ts index 3ae4bef..c847284 100644 --- a/src/formats/dm-unsigned-suffixed-hemisphere-format.ts +++ b/src/formats/dm-unsigned-suffixed-hemisphere-format.ts @@ -49,9 +49,6 @@ export class DmUnsignedSuffixedHemisphereFormat extends BaseFormat { /** * Converts a DMS notation coordinate like "4007.38N" to DMS parts. - * - * @param {string} value - The parsed DMS value, e.g. "4007.38N" or "74007.38W" - * @return {import('../types').openaip.CoordinateParser.DmsCoordinate} */ toDms(value: string): DmsCoordinate { validateSchema(value, z.string(), { assert: true, name: 'value' }); diff --git a/src/formats/dms-signed-prefixed-hemisphere-format.ts b/src/formats/dms-signed-prefixed-hemisphere-format.ts new file mode 100644 index 0000000..455f892 --- /dev/null +++ b/src/formats/dms-signed-prefixed-hemisphere-format.ts @@ -0,0 +1,81 @@ +import { z } from 'zod'; +import type { Coordinate } from '../types.js'; +import { validateSchema } from '../validate-schema.js'; +import { BaseFormat } from './base-format.js'; + +const REGEX = /^([NS])\s*(\d+)°\s*(\d+)'\s*(\d+(?:\.\d+)?)\"\s*,?\s*([EW])\s*(\d+)°\s*(\d+)'\s*(\d+(?:\.\d+)?)\"$/; + +/** + * Parses coordinates strings in DMS signed prefixed hemisphere format. Coordinate ordering is + * always latitude, longitude. + * + * Supported formats: + * + * N40°7'23" W74°7'23" + * N40°7'23", W74°7'23" + * N40°7'23"W74°7'23" + * N 40°7'23.123" W 74°7'23.123" + */ +export class DmsSignedPrefixedHemisphereFormat extends BaseFormat { + parse(coordinateString: string): Coordinate { + validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' }); + + if (DmsSignedPrefixedHemisphereFormat.canParse(coordinateString) === false) { + throw new Error('Invalid coordinate string'); + } + // use the regex to parse the latitude and longitude + const match = coordinateString.match(REGEX); + if (match == null) { + throw new Error('Invalid coordinate string'); + } + const matchLatDegree = match[2]; + const matchLatMinutes = match[3]; + const matchLatSeconds = match[4]; + const matchLatDirection = match[1]; + const matchLonDegree = match[6]; + const matchLonMinutes = match[7]; + const matchLonSeconds = match[8]; + const matchLonDirection = match[5]; + + this.enforceValidLatitudeDegrees(matchLatDegree, false); + this.enforceValidMinutes(matchLatMinutes); + this.enforceValidSeconds(matchLatSeconds); + this.enforceValidLongitudeDegrees(matchLonDegree, false); + this.enforceValidMinutes(matchLonMinutes); + this.enforceValidSeconds(matchLonSeconds); + + const latDegree = Number.parseInt(matchLatDegree); + const latMinutes = Number.parseInt(matchLatMinutes); + const latSeconds = Number.parseFloat(matchLatSeconds); + const lonDegree = Number.parseInt(matchLonDegree); + const lonMinutes = Number.parseInt(matchLonMinutes); + const lonSeconds = Number.parseFloat(matchLonSeconds); + + const decimalLat = this.dmsToDecimal({ + degrees: Math.abs(latDegree), + minutes: latMinutes, + seconds: latSeconds, + direction: matchLatDirection, + }); + const decimalLon = this.dmsToDecimal({ + degrees: Math.abs(lonDegree), + minutes: lonMinutes, + seconds: lonSeconds, + direction: matchLonDirection, + }); + + const lat = decimalLat.toFixed(this.precision); + const lon = decimalLon.toFixed(this.precision); + + return { + latitude: parseFloat(lat), + longitude: parseFloat(lon), + }; + } + + static canParse(coordinateString: string): boolean { + validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' }); + + return REGEX.test(coordinateString); + } +} diff --git a/src/formats/dms-signed-suffixed-hemisphere-format.ts b/src/formats/dms-signed-suffixed-hemisphere-format.ts new file mode 100644 index 0000000..d477053 --- /dev/null +++ b/src/formats/dms-signed-suffixed-hemisphere-format.ts @@ -0,0 +1,81 @@ +import { z } from 'zod'; +import type { Coordinate } from '../types.js'; +import { validateSchema } from '../validate-schema.js'; +import { BaseFormat } from './base-format.js'; + +const REGEX = /^(\d+)°\s*(\d+)'\s*(\d+(?:\.\d+)?)\"\s*([NS])\s*,?\s*(\d+)°\s*(\d+)'\s*(\d+(?:\.\d+)?)\"\s*([EW])$/; + +/** + * Parses coordinates strings in DMS signed suffixed hemisphere format. Coordinate ordering is + * always latitude, longitude. + * + * Supported formats: + * + * 40°7'23"N 74°7'23"W + * 40°7'23"N, 74°7'23"W + * 40°7'23"N74°7'23"W + * 40°7'23.123"N 74°7'23.123"W + */ +export class DmsSignedSuffixedHemisphereFormat extends BaseFormat { + parse(coordinateString: string): Coordinate { + validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' }); + + if (DmsSignedSuffixedHemisphereFormat.canParse(coordinateString) === false) { + throw new Error('Invalid coordinate string'); + } + // use the regex to parse the latitude and longitude + const match = coordinateString.match(REGEX); + if (match == null) { + throw new Error('Invalid coordinate string'); + } + const matchLatDegree = match[1]; + const matchLatMinutes = match[2]; + const matchLatSeconds = match[3]; + const matchLatDirection = match[4]; + const matchLonDegree = match[5]; + const matchLonMinutes = match[6]; + const matchLonSeconds = match[7]; + const matchLonDirection = match[8]; + + this.enforceValidLatitudeDegrees(matchLatDegree, false); + this.enforceValidMinutes(matchLatMinutes); + this.enforceValidSeconds(matchLatSeconds); + this.enforceValidLongitudeDegrees(matchLonDegree, false); + this.enforceValidMinutes(matchLonMinutes); + this.enforceValidSeconds(matchLonSeconds); + + const latDegree = Number.parseInt(matchLatDegree); + const latMinutes = Number.parseInt(matchLatMinutes); + const latSeconds = Number.parseFloat(matchLatSeconds); + const lonDegree = Number.parseInt(matchLonDegree); + const lonMinutes = Number.parseInt(matchLonMinutes); + const lonSeconds = Number.parseFloat(matchLonSeconds); + + const decimalLat = this.dmsToDecimal({ + degrees: Math.abs(latDegree), + minutes: latMinutes, + seconds: latSeconds, + direction: matchLatDirection, + }); + const decimalLon = this.dmsToDecimal({ + degrees: Math.abs(lonDegree), + minutes: lonMinutes, + seconds: lonSeconds, + direction: matchLonDirection, + }); + + const lat = decimalLat.toFixed(this.precision); + const lon = decimalLon.toFixed(this.precision); + + return { + latitude: parseFloat(lat), + longitude: parseFloat(lon), + }; + } + + static canParse(coordinateString: string): boolean { + validateSchema(coordinateString, z.string(), { assert: true, name: 'coordinateString' }); + + return REGEX.test(coordinateString); + } +} diff --git a/src/parser.ts b/src/parser.ts index dfde7cb..e8d2f96 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -9,6 +9,8 @@ import { DecimalUnsignedSuffixedHemisphereFormat } from './formats/decimal-unsig import { DmUnsignedPrefixedHemisphereFormat } from './formats/dm-unsigned-prefixed-hemisphere-format.js'; import { DmUnsignedSuffixedHemisphereFormat } from './formats/dm-unsigned-suffixed-hemisphere-format.js'; import { DmsSignedFormat } from './formats/dms-signed-format.js'; +import { DmsSignedPrefixedHemisphereFormat } from './formats/dms-signed-prefixed-hemisphere-format.js'; +import { DmsSignedSuffixedHemisphereFormat } from './formats/dms-signed-suffixed-hemisphere-format.js'; import { DmsUnsignedFormat } from './formats/dms-unsigned-format.js'; import type { Coordinate } from './types.js'; import { validateSchema } from './validate-schema.js'; @@ -55,6 +57,8 @@ export class Parser { new DmUnsignedPrefixedHemisphereFormat({ precision: precision }), new DmUnsignedSuffixedHemisphereFormat({ precision: precision }), new DmsSignedFormat({ precision: precision }), + new DmsSignedPrefixedHemisphereFormat({ precision: precision }), + new DmsSignedSuffixedHemisphereFormat({ precision: precision }), new DmsUnsignedFormat({ precision: precision }), ]; let formatParsers = options?.formatParsers || defaultParsers; diff --git a/tests/decimal-signed-format.test.ts b/tests/decimal-signed-format.test.ts index b988469..731e607 100644 --- a/tests/decimal-signed-format.test.ts +++ b/tests/decimal-signed-format.test.ts @@ -6,10 +6,6 @@ describe('canParse', () => { expect(DecimalSignedFormat.canParse('1.234° 5.678°')).toBe(true); expect(DecimalSignedFormat.canParse('1.234 °, 5.678 °')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DecimalSignedFormat.canParse('1.234 5.678')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for '12° 5°'", () => { diff --git a/tests/decimal-signed-prefixed-hemisphere-format.test.ts b/tests/decimal-signed-prefixed-hemisphere-format.test.ts index c8bd9ae..cfa8646 100644 --- a/tests/decimal-signed-prefixed-hemisphere-format.test.ts +++ b/tests/decimal-signed-prefixed-hemisphere-format.test.ts @@ -9,12 +9,6 @@ describe('canParse', () => { expect(DecimalSignedPrefixedHemisphereFormat.canParse('N 1.234°,E5.678°')).toBe(true); expect(DecimalSignedPrefixedHemisphereFormat.canParse('N1.234°E5.678°')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DecimalSignedPrefixedHemisphereFormat.canParse('1.234 5.678')).toBe(false); - expect(DecimalSignedPrefixedHemisphereFormat.canParse('1.234 N 5.678 P')).toBe(false); - expect(DecimalSignedPrefixedHemisphereFormat.canParse('1.234 N 5.678 ')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for 'N 12° E 5°'", () => { diff --git a/tests/decimal-signed-suffixed-hemisphere-format.test.ts b/tests/decimal-signed-suffixed-hemisphere-format.test.ts index 69369b0..9c1fe30 100644 --- a/tests/decimal-signed-suffixed-hemisphere-format.test.ts +++ b/tests/decimal-signed-suffixed-hemisphere-format.test.ts @@ -10,12 +10,6 @@ describe('canParse', () => { expect(DecimalSignedSuffixedHemisphereFormat.canParse('1.234°N,5.678°E')).toBe(true); expect(DecimalSignedSuffixedHemisphereFormat.canParse('1.234°N5.678°E')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DecimalSignedSuffixedHemisphereFormat.canParse('1.234 5.678')).toBe(false); - expect(DecimalSignedSuffixedHemisphereFormat.canParse('1.234 N 5.678 P')).toBe(false); - expect(DecimalSignedSuffixedHemisphereFormat.canParse('1.234 N 5.678 ')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for '12° N 5° E'", () => { diff --git a/tests/decimal-unsigned-format.test.ts b/tests/decimal-unsigned-format.test.ts index e7eb724..06be9f2 100644 --- a/tests/decimal-unsigned-format.test.ts +++ b/tests/decimal-unsigned-format.test.ts @@ -6,10 +6,6 @@ describe('canParse', () => { expect(DecimalUnsignedFormat.canParse('1.234, 5.678')).toBe(true); expect(DecimalUnsignedFormat.canParse('1.234 5.678')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DecimalUnsignedFormat.canParse('1.234N 5.678E')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for '10, 13'", () => { diff --git a/tests/decimal-unsigned-prefixed-hemisphere-format.test.ts b/tests/decimal-unsigned-prefixed-hemisphere-format.test.ts index a419209..e93ddd7 100644 --- a/tests/decimal-unsigned-prefixed-hemisphere-format.test.ts +++ b/tests/decimal-unsigned-prefixed-hemisphere-format.test.ts @@ -9,10 +9,6 @@ describe('canParse', () => { expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N12.234,E56.678')).toBe(true); expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('N12.234E56.678')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DecimalUnsignedPrefixedHemisphereFormat.canParse('1.234 5.678')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for 'N12 E56'", () => { diff --git a/tests/decimal-unsigned-suffixed-hemisphere-format.test.ts b/tests/decimal-unsigned-suffixed-hemisphere-format.test.ts index 56c9120..40a2865 100644 --- a/tests/decimal-unsigned-suffixed-hemisphere-format.test.ts +++ b/tests/decimal-unsigned-suffixed-hemisphere-format.test.ts @@ -9,10 +9,6 @@ describe('canParse', () => { expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12.234N,56.678E')).toBe(true); expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('12.234N56.678E')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DecimalUnsignedSuffixedHemisphereFormat.canParse('1.234 5.678')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for '12N 56E'", () => { diff --git a/tests/dm-unsigned-prefixed-hemisphere-format.test.ts b/tests/dm-unsigned-prefixed-hemisphere-format.test.ts index ed05254..26e7eec 100644 --- a/tests/dm-unsigned-prefixed-hemisphere-format.test.ts +++ b/tests/dm-unsigned-prefixed-hemisphere-format.test.ts @@ -8,12 +8,6 @@ describe('canParse', () => { expect(DmUnsignedPrefixedHemisphereFormat.canParse('N 4007.38 W 7407.38')).toBe(true); expect(DmUnsignedPrefixedHemisphereFormat.canParse('N4007.38 W7407.38')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DmUnsignedPrefixedHemisphereFormat.canParse('4007.38N740738W')).toBe(false); - expect(DmUnsignedPrefixedHemisphereFormat.canParse('4007.38N7407.38P')).toBe(false); - expect(DmUnsignedPrefixedHemisphereFormat.canParse('4007.38N7407.38 ')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for 'N4007 W7407'", () => { diff --git a/tests/dm-unsigned-suffixed-hemisphere-format.test.ts b/tests/dm-unsigned-suffixed-hemisphere-format.test.ts index 8e2e48a..f90aab9 100644 --- a/tests/dm-unsigned-suffixed-hemisphere-format.test.ts +++ b/tests/dm-unsigned-suffixed-hemisphere-format.test.ts @@ -8,12 +8,6 @@ describe('canParse', () => { expect(DmUnsignedSuffixedHemisphereFormat.canParse('4007.38 N 7407.38 W')).toBe(true); expect(DmUnsignedSuffixedHemisphereFormat.canParse('4007.38N 7407.38W')).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DmUnsignedSuffixedHemisphereFormat.canParse('4007.38N740738W')).toBe(false); - expect(DmUnsignedSuffixedHemisphereFormat.canParse('4007.38N7407.38P')).toBe(false); - expect(DmUnsignedSuffixedHemisphereFormat.canParse('4007.38N7407.38 ')).toBe(false); - }); }); describe('parse', () => { it("returns the correct latitude and longitude for '4007N 7407W'", () => { diff --git a/tests/dms-signed-format.test.ts b/tests/dms-signed-format.test.ts index 24754fd..fc20b5c 100644 --- a/tests/dms-signed-format.test.ts +++ b/tests/dms-signed-format.test.ts @@ -10,10 +10,6 @@ describe('canParse', () => { expect(DmsSignedFormat.canParse(`40° 7' 23", -74° 7' 23"`)).toBe(true); expect(DmsSignedFormat.canParse(`40° 7' 23.9999", -74° 7' 23.9999"`)).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DmsSignedFormat.canParse('1.234 5.678')).toBe(false); - }); }); describe('parse', () => { it(`returns the correct latitude and longitude for 40°7'23" -74°7'23"`, () => { diff --git a/tests/dms-signed-prefixed-hemisphereformat.test.ts b/tests/dms-signed-prefixed-hemisphereformat.test.ts new file mode 100644 index 0000000..c080f0c --- /dev/null +++ b/tests/dms-signed-prefixed-hemisphereformat.test.ts @@ -0,0 +1,65 @@ +import { describe, expect, it } from 'vitest'; +import { DmsSignedPrefixedHemisphereFormat } from '../src/formats/dms-signed-prefixed-hemisphere-format.js'; + +describe('canParse', () => { + it('returns true for known formats', () => { + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N40°7'23" W74°7'23"`)).toBe(true); + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N40°7'23"W74°7'23"`)).toBe(true); + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N 40° 7' 23" W 74° 7' 23"`)).toBe(true); + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N40°7'23", W74°7'23"`)).toBe(true); + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N40°7'23",W74°7'23"`)).toBe(true); + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N40° 7' 23", W74° 7' 23"`)).toBe(true); + expect(DmsSignedPrefixedHemisphereFormat.canParse(`N 40° 7' 23.9999", W 74° 7' 23.9999"`)).toBe(true); + }); +}); +describe('parse', () => { + it(`returns the correct latitude and longitude for N40°7'23" W74°7'23"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat(); + const result = formatParser.parse(`N40°7'23" W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40°7'23"W74°7'23"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat(); + const result = formatParser.parse(`N40°7'23"W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N 40° 7' 23" W 74° 7' 23"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat(); + const result = formatParser.parse(`N 40° 7' 23" W 74° 7' 23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40°7'23", W74°7'23"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat(); + const result = formatParser.parse(`N40°7'23", W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40°7'23",W74°7'23"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat(); + const result = formatParser.parse(`N40°7'23",W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40° 7' 23", W74° 7' 23"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat(); + const result = formatParser.parse(`N40° 7' 23", W74° 7' 23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N 40° 7' 23.9999", W 74° 7' 23.9999"`, () => { + const formatParser = new DmsSignedPrefixedHemisphereFormat({ precision: 5 }); + const result = formatParser.parse(`N 40° 7' 23.9999", W 74° 7' 23.9999"`); + + expect(result.latitude).toBe(40.12333); + expect(result.longitude).toBe(-74.12333); + }); +}); diff --git a/tests/dms-signed-suffixed-hemisphereformat.test.ts b/tests/dms-signed-suffixed-hemisphereformat.test.ts new file mode 100644 index 0000000..6833cd9 --- /dev/null +++ b/tests/dms-signed-suffixed-hemisphereformat.test.ts @@ -0,0 +1,65 @@ +import { describe, expect, it } from 'vitest'; +import { DmsSignedSuffixedHemisphereFormat } from '../src/formats/dms-signed-suffixed-hemisphere-format.js'; + +describe('canParse', () => { + it('returns true for known formats', () => { + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40°7'23"N 74°7'23"W`)).toBe(true); + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40°7'23"N74°7'23"W`)).toBe(true); + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40° 7' 23" N 74° 7' 23" W`)).toBe(true); + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40°7'23"N, 74°7'23"W`)).toBe(true); + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40°7'23"N,74°7'23"W`)).toBe(true); + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40° 7' 23" N, 74° 7' 23" W`)).toBe(true); + expect(DmsSignedSuffixedHemisphereFormat.canParse(`40° 7' 23.9999" N, 74° 7' 23.9999" W`)).toBe(true); + }); +}); +describe('parse', () => { + it(`returns the correct latitude and longitude for 40°7'23"N 74°7'23"W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat(); + const result = formatParser.parse(`40°7'23"N 74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40°7'23"N74°7'23"W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat(); + const result = formatParser.parse(`40°7'23"N74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40° 7' 23" N 74° 7' 23" W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat(); + const result = formatParser.parse(`40° 7' 23" N 74° 7' 23" W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40°7'23"N, 74°7'23"W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat(); + const result = formatParser.parse(`40°7'23"N, 74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40°7'23"N,74°7'23"W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat(); + const result = formatParser.parse(`40°7'23"N,74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40° 7' 23" N, 74° 7' 23" W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat(); + const result = formatParser.parse(`40° 7' 23" N, 74° 7' 23" W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40° 7' 23.9999" N, 74° 7' 23.9999" W`, () => { + const formatParser = new DmsSignedSuffixedHemisphereFormat({ precision: 5 }); + const result = formatParser.parse(`40° 7' 23.9999" N, 74° 7' 23.9999" W`); + + expect(result.latitude).toBe(40.12333); + expect(result.longitude).toBe(-74.12333); + }); +}); diff --git a/tests/dms-unsigned-format.test.ts b/tests/dms-unsigned-format.test.ts index 10d4029..4db28dc 100644 --- a/tests/dms-unsigned-format.test.ts +++ b/tests/dms-unsigned-format.test.ts @@ -10,10 +10,6 @@ describe('canParse', () => { expect(DmsUnsignedFormat.canParse(`40 7 23, -74 7 23`)).toBe(true); expect(DmsUnsignedFormat.canParse(`40 7 23.9999, -74 7 23.9999`)).toBe(true); }); - - it('returns false for unknown formats', () => { - expect(DmsUnsignedFormat.canParse('1.234 5.678')).toBe(false); - }); }); describe('parse', () => { it(`returns the correct latitude and longitude for 40 7 23 -74 7 23`, () => { diff --git a/tests/parser.test.ts b/tests/parser.test.ts index 0e44ae5..55b96af 100644 --- a/tests/parser.test.ts +++ b/tests/parser.test.ts @@ -290,7 +290,6 @@ describe('Test that all configured format parsers do not interfere', () => { expect(result.longitude).toBe(-74.123); }); }); - describe('test dsm signed format', () => { it(`returns the correct latitude and longitude for 40°7'23" -74°7'23"`, () => { const parser = new Parser(); @@ -379,5 +378,106 @@ describe('Test that all configured format parsers do not interfere', () => { expect(result.longitude).toBe(-74.12333); }); }); + describe('test dms signed prefixed hemisphere format', () => { + it(`returns the correct latitude and longitude for N40°7'23" W74°7'23"`, () => { + const parser = new Parser(); + const result = parser.parse(`N40°7'23" W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40°7'23"W74°7'23"`, () => { + const parser = new Parser(); + const result = parser.parse(`N40°7'23"W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N 40° 7' 23" W 74° 7' 23"`, () => { + const parser = new Parser(); + const result = parser.parse(`N 40° 7' 23" W 74° 7' 23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40°7'23", W74°7'23"`, () => { + const parser = new Parser(); + const result = parser.parse(`N40°7'23", W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40°7'23",W74°7'23"`, () => { + const parser = new Parser(); + const result = parser.parse(`N40°7'23",W74°7'23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N40° 7' 23", W74° 7' 23"`, () => { + const parser = new Parser(); + const result = parser.parse(`N40° 7' 23", W74° 7' 23"`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for N 40° 7' 23.9999", W 74° 7' 23.9999"`, () => { + const parser = new Parser({ precision: 5 }); + const result = parser.parse(`N 40° 7' 23.9999", W 74° 7' 23.9999"`); + expect(result.latitude).toBe(40.12333); + expect(result.longitude).toBe(-74.12333); + }); + }); + describe('test dms signed suffixed hemisphere format', () => { + it(`returns the correct latitude and longitude for 40°7'23"N 74°7'23"W`, () => { + const parser = new Parser(); + const result = parser.parse(`40°7'23"N 74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40°7'23"N74°7'23"W`, () => { + const parser = new Parser(); + const result = parser.parse(`40°7'23"N74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40° 7' 23" N 74° 7' 23" W`, () => { + const parser = new Parser(); + const result = parser.parse(`40° 7' 23" N 74° 7' 23" W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40°7'23"N, 74°7'23"W`, () => { + const parser = new Parser(); + const result = parser.parse(`40°7'23"N, 74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40°7'23"N,74°7'23"W`, () => { + const parser = new Parser(); + const result = parser.parse(`40°7'23"N,74°7'23"W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40° 7' 23" N, 74° 7' 23" W`, () => { + const parser = new Parser(); + const result = parser.parse(`40° 7' 23" N, 74° 7' 23" W`); + expect(result.latitude).toBe(40.123); + expect(result.longitude).toBe(-74.123); + }); + + it(`returns the correct latitude and longitude for 40° 7' 23.9999" N, 74° 7' 23.9999" W`, () => { + const parser = new Parser({ precision: 5 }); + const result = parser.parse(`40° 7' 23.9999" N, 74° 7' 23.9999" W`); + + expect(result.latitude).toBe(40.12333); + expect(result.longitude).toBe(-74.12333); + }); + }); // describe('test', () => {}); });