package ridetest import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRideSingleSection(t *testing.T) { r, err := Ride("1km at 10%") require.NoError(t, err) assert.Len(t, r.Distances(), 11) assert.Equal(t, 0.0, r.Distances()[0]) assert.Equal(t, 1000.0, r.Distances()[10]) assert.Equal(t, 0.0, r.Elevations()[0]) assert.Equal(t, 100.0, r.Elevations()[10]) } func TestRideSectionsWithDescentAndFlat(t *testing.T) { r, err := Ride("0.5km at 10% | 0.5km at -10%") require.NoError(t, err) assert.Len(t, r.Distances(), 11) assert.Equal(t, 1000.0, r.Distances()[10]) assert.Equal(t, 50.0, r.Elevations()[5]) // top of the first section assert.Equal(t, 0.0, r.Elevations()[10]) // back to start elevation } func TestRideSamplingOption(t *testing.T) { r, err := Ride("1km at 10%", Sampling(50)) require.NoError(t, err) assert.Len(t, r.Distances(), 21) assert.Equal(t, 1000.0, r.Distances()[20]) assert.Equal(t, 5.0, r.Elevations()[1]) } func TestRideStartCoordHeading(t *testing.T) { r, err := Ride("2km at 0%", StartCoord(43.10, 5.10), Sampling(1000)) require.NoError(t, err) // Coordinates advance northeast by 0.01° per km; float64 literals like // 43.11 drift in the last bits, so compare with a small tolerance. require.Len(t, r.Coords(), 3) assert.InDelta(t, 43.10, r.Coords()[0].Lat, 1e-9) assert.InDelta(t, 5.10, r.Coords()[0].Lon, 1e-9) assert.InDelta(t, 43.11, r.Coords()[1].Lat, 1e-9) assert.InDelta(t, 5.11, r.Coords()[1].Lon, 1e-9) assert.InDelta(t, 43.12, r.Coords()[2].Lat, 1e-9) assert.InDelta(t, 5.12, r.Coords()[2].Lon, 1e-9) } func TestRideStartTime(t *testing.T) { start := time.Date(2026, 8, 1, 10, 0, 0, 0, time.UTC) r, err := Ride("1km at 0%", StartTime(start), Sampling(500)) require.NoError(t, err) assert.Len(t, r.Timestamps(), 3) assert.Equal(t, start, r.Timestamps()[0]) assert.Equal(t, start.Add(time.Second), r.Timestamps()[1]) assert.Equal(t, start.Add(2*time.Second), r.Timestamps()[2]) } func TestRideStartElevation(t *testing.T) { r, err := Ride("1km at 0%", StartElevation(100)) require.NoError(t, err) assert.Equal(t, 100.0, r.Elevations()[0]) assert.Equal(t, 100.0, r.Elevations()[10]) } func TestRideMetricsCompleteColumns(t *testing.T) { r, err := Ride("0.5km at 0% hr=150 cad=80 w=200 | 0.5km at 0% hr=140 cad=70 w=150") require.NoError(t, err) heartRates, ok := r.HeartRates() require.True(t, ok) assert.Equal(t, 150.0, heartRates[0]) assert.Equal(t, 150.0, heartRates[5]) assert.Equal(t, 140.0, heartRates[6]) assert.Equal(t, 140.0, heartRates[10]) cadences, ok := r.Cadences() require.True(t, ok) assert.Equal(t, 80.0, cadences[0]) assert.Equal(t, 70.0, cadences[10]) powers, ok := r.Powers() require.True(t, ok) assert.Equal(t, 200.0, powers[0]) assert.Equal(t, 150.0, powers[10]) } func TestRideMetricsWithoutOptions(t *testing.T) { r, err := Ride("1km at 0%") require.NoError(t, err) _, ok := r.HeartRates() assert.False(t, ok) _, ok = r.Cadences() assert.False(t, ok) _, ok = r.Powers() assert.False(t, ok) } func TestRideMetricsPartialColumnFails(t *testing.T) { _, err := Ride("0.5km at 0% hr=150 | 0.5km at 0%") require.Error(t, err) assert.Contains(t, err.Error(), "hr=") } func TestRideParseErrors(t *testing.T) { cases := []string{ "", " ", "|", "1km at 0% |", "at 7%", "1km 7%", "0km at 7%", "-1km at 7%", "1km at abc%", "xyz at 7%", "1km away 7%", "1km at 7% foo=1", "1km at 7% hr=abc", } for _, dsl := range cases { _, err := Ride(dsl) require.Error(t, err, "dsl %q", dsl) } } func TestRideRejectsNonPositiveSampling(t *testing.T) { _, err := Ride("1km at 0%", Sampling(0)) require.Error(t, err) _, err = Ride("1km at 0%", Sampling(-10)) require.Error(t, err) } func TestMustRidePanicsOnMalformedDSL(t *testing.T) { assert.Panics(t, func() { MustRide("nope") }) }