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);
});
});
});