const assert = require('assert'); const { parseAndCompress } = require('../src/utils/gpx-processor'); function makeGPX(points, name = 'Test Track') { const trkpts = points.map(p => { const timeTag = p.time ? `` : ''; const eleTag = p.ele != null ? `${p.ele}` : ''; return `${eleTag}${timeTag}`; }).join('\n'); return ` ${name} ${trkpts} `; } describe('GPX processor', () => { describe('parseAndCompress', () => { it('parses a minimal GPX and returns correct structure', async () => { const gpx = makeGPX([ { lat: 51.5, lon: -0.1, ele: 10, time: '2024-01-01T10:00:00Z' }, { lat: 51.501, lon: -0.1, ele: 11, time: '2024-01-01T10:01:00Z' }, ], 'My Track'); const result = await parseAndCompress(gpx); assert.strictEqual(result.trackName, 'My Track'); assert.ok(result.segments.length > 0); assert.ok(result.pointCount >= 2); assert.ok(result.totalDistance > 0); }); it('sets trackDate from first point timestamp', async () => { const gpx = makeGPX([ { lat: 51.5, lon: -0.1, time: '2024-06-15T08:30:00Z' }, { lat: 51.51, lon: -0.1, time: '2024-06-15T09:00:00Z' }, ]); const result = await parseAndCompress(gpx); assert.ok(result.trackDate instanceof Date); assert.strictEqual(result.trackDate.getFullYear(), 2024); assert.strictEqual(result.trackDate.getMonth(), 5); // June = 5 (0-indexed) }); it('skips points closer than 2 m', async () => { // Points almost on top of each other (< 2m apart) const gpx = makeGPX([ { lat: 51.5000000, lon: -0.1, time: '2024-01-01T10:00:00Z' }, { lat: 51.5000001, lon: -0.1, time: '2024-01-01T10:00:30Z' }, // ~1 cm away { lat: 51.5000002, lon: -0.1, time: '2024-01-01T10:01:00Z' }, // still < 2m from first { lat: 51.5010000, lon: -0.1, time: '2024-01-01T10:01:30Z' }, // ~111 m away ]); const result = await parseAndCompress(gpx); // Should keep first, skip tiny points, keep last far point assert.ok(result.pointCount < 4, `Expected fewer than 4 points, got ${result.pointCount}`); assert.ok(result.pointCount >= 2); }); it('skips points with < 30s gap (no sharp turn)', async () => { // Points 10s apart in a straight line - should be skipped const gpx = makeGPX([ { lat: 51.500, lon: -0.100, time: '2024-01-01T10:00:00Z' }, { lat: 51.501, lon: -0.100, time: '2024-01-01T10:00:10Z' }, // 10s gap, straight line { lat: 51.502, lon: -0.100, time: '2024-01-01T10:00:20Z' }, // 10s gap, straight line { lat: 51.503, lon: -0.100, time: '2024-01-01T10:01:00Z' }, // 40s gap, should keep ]); const result = await parseAndCompress(gpx); // Middle points should be mostly skipped due to < 30s and no sharp turn assert.ok(result.pointCount <= 3, `Expected ≤3 points, got ${result.pointCount}`); }); it('keeps points with < 30s gap if sharp turn', async () => { // U-turn: going north then suddenly south const gpx = makeGPX([ { lat: 51.500, lon: -0.100, time: '2024-01-01T10:00:00Z' }, { lat: 51.510, lon: -0.100, time: '2024-01-01T10:00:10Z' }, // 10s, going north { lat: 51.500, lon: -0.100, time: '2024-01-01T10:00:20Z' }, // 10s, sharp turn back south { lat: 51.490, lon: -0.100, time: '2024-01-01T10:01:00Z' }, // continuing south ]); const result = await parseAndCompress(gpx); // The middle point (apex of U-turn) should be kept assert.ok(result.pointCount >= 3, `Expected ≥3 points (turn apex kept), got ${result.pointCount}`); }); it('keeps points at >= 30s intervals regardless of distance', async () => { const gpx = makeGPX([ { lat: 51.500, lon: -0.100, time: '2024-01-01T10:00:00Z' }, { lat: 51.501, lon: -0.100, time: '2024-01-01T10:00:30Z' }, // exactly 30s { lat: 51.502, lon: -0.100, time: '2024-01-01T10:01:00Z' }, // 30s later ]); const result = await parseAndCompress(gpx); assert.strictEqual(result.pointCount, 3); }); it('handles GPX with no timestamps', async () => { const gpx = makeGPX([ { lat: 51.500, lon: -0.100 }, { lat: 51.510, lon: -0.100 }, { lat: 51.520, lon: -0.100 }, ]); const result = await parseAndCompress(gpx); assert.ok(result.pointCount >= 2); assert.strictEqual(result.trackDate, null); }); it('calculates total distance correctly', async () => { // Two points ~111m apart (0.001 degree lat) const gpx = makeGPX([ { lat: 51.5000, lon: 0, time: '2024-01-01T10:00:00Z' }, { lat: 51.5010, lon: 0, time: '2024-01-01T10:01:00Z' }, ]); const result = await parseAndCompress(gpx); assert.ok(result.totalDistance > 100 && result.totalDistance < 120, `Expected ~111 m, got ${result.totalDistance.toFixed(1)} m`); }); it('handles multiple segments', async () => { const xml = ` Multi Segment `; const result = await parseAndCompress(xml); assert.strictEqual(result.segments.length, 2); assert.ok(result.pointCount >= 4); }); }); });