Initial
This commit is contained in:
commit
b43955e0d9
162 changed files with 15425 additions and 0 deletions
88
tests/unit/telemetry.test.ts
Normal file
88
tests/unit/telemetry.test.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { parseTelemetry, computeDeviations, distHaversine, parsePrediction } from '$domain';
|
||||
import type { TelemetryPoint, PredictionStage } from '$domain';
|
||||
|
||||
const points: TelemetryPoint[] = [
|
||||
{ latitude: 62.0, longitude: 129.0, altitude: 0, datetime: '2026-01-01T00:00:00Z', payload: '{}' },
|
||||
{
|
||||
latitude: 62.05,
|
||||
longitude: 129.1,
|
||||
altitude: 15000,
|
||||
datetime: '2026-01-01T00:30:00Z',
|
||||
payload: '{}'
|
||||
}
|
||||
];
|
||||
|
||||
describe('parseTelemetry', () => {
|
||||
it('builds a flight path and takes the first sample as launch', () => {
|
||||
const t = parseTelemetry(points);
|
||||
expect(t.flight_path).toEqual([
|
||||
[62.0, 129.0, 0],
|
||||
[62.05, 129.1, 15000]
|
||||
]);
|
||||
expect(t.launch.latlng.lat).toBe(62.0);
|
||||
expect(t.datapoints).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('throws on an empty series', () => {
|
||||
expect(() => parseTelemetry([])).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('distHaversine', () => {
|
||||
it('is zero for identical points and ~343 km London→Paris', () => {
|
||||
expect(distHaversine({ lat: 55, lng: 37 }, { lat: 55, lng: 37 })).toBe(0);
|
||||
const d = distHaversine({ lat: 51.5074, lng: -0.1278 }, { lat: 48.8566, lng: 2.3522 });
|
||||
expect(d).toBeGreaterThan(340);
|
||||
expect(d).toBeLessThan(346);
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeDeviations', () => {
|
||||
// Prediction runs 00:00 → 01:30 along the same corridor as the telemetry.
|
||||
const stages: PredictionStage[] = [
|
||||
{
|
||||
stage: 'ascent',
|
||||
trajectory: [
|
||||
{ altitude: 0, datetime: '2026-01-01T00:00:00Z', latitude: 62.0, longitude: 129.0 },
|
||||
{ altitude: 30000, datetime: '2026-01-01T01:00:00Z', latitude: 62.1, longitude: 129.2 }
|
||||
]
|
||||
},
|
||||
{
|
||||
stage: 'descent',
|
||||
trajectory: [
|
||||
{ altitude: 30000, datetime: '2026-01-01T01:00:00Z', latitude: 62.1, longitude: 129.2 },
|
||||
{ altitude: 0, datetime: '2026-01-01T01:30:00Z', latitude: 62.05, longitude: 129.4 }
|
||||
]
|
||||
}
|
||||
];
|
||||
const prediction = parsePrediction(stages);
|
||||
|
||||
it('matches each sample to the closest prediction point', () => {
|
||||
const devs = computeDeviations(points, prediction);
|
||||
expect(devs).toHaveLength(2);
|
||||
// First sample sits exactly on the predicted launch point.
|
||||
expect(devs[0].horizontal).toBeCloseTo(0, 6);
|
||||
expect(devs[0].vertical).toBe(0);
|
||||
// Second sample is offset from the prediction, both laterally and in altitude.
|
||||
expect(devs[1].horizontal).toBeGreaterThan(0);
|
||||
expect(devs[1].altActual).toBe(15000);
|
||||
});
|
||||
|
||||
it('skips samples outside the prediction window', () => {
|
||||
const outside: TelemetryPoint[] = [
|
||||
{
|
||||
latitude: 62,
|
||||
longitude: 129,
|
||||
altitude: 0,
|
||||
datetime: '2025-12-31T00:00:00Z', // a day early
|
||||
payload: '{}'
|
||||
}
|
||||
];
|
||||
expect(computeDeviations(outside, prediction)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns nothing without telemetry', () => {
|
||||
expect(computeDeviations([], prediction)).toEqual([]);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue